C# 没有科学记数法的双字符串转换
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1546113/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Double to string conversion without scientific notation
提问by Lucero
How to convert a double into a floating-point string representation without scientific notation in the .NET Framework?
如何在 .NET Framework 中将 double 转换为没有科学计数法的浮点字符串表示形式?
"Small" samples (effective numbers may be of any size, such as 1.5E200
or 1e-200
) :
“小”样本(有效数字可以是任何大小,例如1.5E200
或1e-200
):
3248971234698200000000000000000000000000000000
0.00000000000000000000000000000000000023897356978234562
None of the standard number formatsare like this, and a custom formatalso doesn't seem to allow having an open number of digits after the decimal separator.
没有任何标准数字格式是这样的,自定义格式似乎也不允许在小数点分隔符后有开放的位数。
This is not a duplicate of How to convert double to string without the power to 10 representation (E-05)because the answers given there do notsolve the issue at hand. The accepted solution in this question was to use a fixed point (such as 20 digits), which is not what I want. A fixed point formatting and trimming the redundant 0 doesn't solve the issue either because the max width for fixed width is 99 characters.
这不是How to convert double to string without power to 10 representation (E-05)的副本,因为那里给出的答案并没有解决手头的问题。这个问题中公认的解决方案是使用固定点(例如20位数字),这不是我想要的。定点格式化和修剪多余的 0 也不能解决问题,因为固定宽度的最大宽度为 99 个字符。
Note:the solution has to deal correctly with custom number formats (e.g. other decimal separator, depending on culture information).
注意:解决方案必须正确处理自定义数字格式(例如其他小数点分隔符,取决于文化信息)。
Edit:The question is really only about displaing aforementioned numbers. I'm aware of how floating point numbers work and what numbers can be used and computed with them.
编辑:问题实际上只是关于显示上述数字。我知道浮点数是如何工作的,以及可以使用和计算哪些数字。
采纳答案by jnm2
For a general-purpose1 solution you need to preserve 339 places:
对于通用 1 解决方案,您需要保留 339 个位置:
doubleValue.ToString("0." + new string('#', 339))
doubleValue.ToString("0." + new string('#', 339))
The maximum number of non-zero decimal digits is 16. 15 are on the right side of the decimal point. The exponent can move those 15 digits a maximum of 324 places to the right. (See the range and precision.)
非零十进制数字的最大位数为 16。15 位在小数点右侧。指数最多可以将这 15 位数字向右移动 324 位。(见范围和精度。)
It works for double.Epsilon
, double.MinValue
, double.MaxValue
, and anything in between.
它适用于double.Epsilon
、double.MinValue
、double.MaxValue
以及介于两者之间的任何内容。
The performance will be much greater than the regex/string manipulation solutions since all formatting and string work is done in one pass by unmanaged CLR code. Also, the code is much simpler to prove correct.
性能将远高于正则表达式/字符串操作解决方案,因为所有格式化和字符串工作都由非托管 CLR 代码一次性完成。此外,代码更容易证明正确。
For ease of use and even better performance, make it a constant:
为了便于使用和更好的性能,请将其设为常量:
public static class FormatStrings
{
public const string DoubleFixedPoint = "0.###################################################################################################################################################################################################################################################################################################################################################";
}
1 Update:I mistakenly said that this was also a lossless solution. In fact it is not, since ToString
does its normal display rounding for all formats except r
. Live example.Thanks, @Loathing! Please see Lothing's answerif you need the ability to roundtrip in fixed point notation (i.e, if you're using .ToString("r")
today).
1更新:我错误地说这也是一种无损解决方案。事实上并非如此,因为ToString
除了r
. 活生生的例子。谢谢,@Loathing!如果您需要能够以定点表示法进行往返(即,如果您今天正在使用),请参阅Lothing 的答案.ToString("r")
。
回答by Lucero
This is what I've got so far, seems to work, but maybe someone has a better solution:
这是我到目前为止所得到的,似乎有效,但也许有人有更好的解决方案:
private static readonly Regex rxScientific = new Regex(@"^(?<sign>-?)(?<head>\d+)(\.(?<tail>\d*?)0*)?E(?<exponent>[+\-]\d+)$", RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture|RegexOptions.CultureInvariant);
public static string ToFloatingPointString(double value) {
return ToFloatingPointString(value, NumberFormatInfo.CurrentInfo);
}
public static string ToFloatingPointString(double value, NumberFormatInfo formatInfo) {
string result = value.ToString("r", NumberFormatInfo.InvariantInfo);
Match match = rxScientific.Match(result);
if (match.Success) {
Debug.WriteLine("Found scientific format: {0} => [{1}] [{2}] [{3}] [{4}]", result, match.Groups["sign"], match.Groups["head"], match.Groups["tail"], match.Groups["exponent"]);
int exponent = int.Parse(match.Groups["exponent"].Value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
StringBuilder builder = new StringBuilder(result.Length+Math.Abs(exponent));
builder.Append(match.Groups["sign"].Value);
if (exponent >= 0) {
builder.Append(match.Groups["head"].Value);
string tail = match.Groups["tail"].Value;
if (exponent < tail.Length) {
builder.Append(tail, 0, exponent);
builder.Append(formatInfo.NumberDecimalSeparator);
builder.Append(tail, exponent, tail.Length-exponent);
} else {
builder.Append(tail);
builder.Append('0', exponent-tail.Length);
}
} else {
builder.Append('0');
builder.Append(formatInfo.NumberDecimalSeparator);
builder.Append('0', (-exponent)-1);
builder.Append(match.Groups["head"].Value);
builder.Append(match.Groups["tail"].Value);
}
result = builder.ToString();
}
return result;
}
// test code
double x = 1.0;
for (int i = 0; i < 200; i++) {
x /= 10;
}
Console.WriteLine(x);
Console.WriteLine(ToFloatingPointString(x));
回答by csharptest.net
I could be wrong, but isn't it like this?
我可能是错的,但不是这样吗?
data.ToString("n");
回答by mfeingold
Just to build on what jcasso said what you can do is to adjust your double value by changing the exponent so that your favorite format would do it for you, apply the format, and than pad the result with zeros to compensate for the adjustment.
只是为了建立在 jcasso 所说的基础上,您可以做的是通过更改指数来调整双精度值,以便您喜欢的格式为您执行此操作,应用格式,然后用零填充结果以补偿调整。
回答by Ed Power
In the old days when we had to write our own formatters, we'd isolate the mantissa and exponent and format them separately.
在过去,当我们必须编写自己的格式化程序时,我们会将尾数和指数分开并分别格式化。
In this article by Jon Skeet (https://csharpindepth.com/articles/FloatingPoint) he provides a link to his DoubleConverter.cs routine that should do exactly what you want. Skeet also refers to this at extracting mantissa and exponent from double in c#.
在 Jon Skeet 的这篇文章 ( https://csharpindepth.com/articles/FloatingPoint) 中,他提供了一个指向他的 DoubleConverter.cs 例程的链接,该例程应该完全符合您的要求。Skeet 在从 c# 中的 double 中提取尾数和指数时也提到了这一点。
回答by Brian
The obligatory Logarithm-based solution. Note that this solution, because it involves doing math, may reduce the accuracy of your number a little bit. Not heavily tested.
基于对数的强制性解决方案。请注意,此解决方案由于涉及数学运算,可能会稍微降低您的数字的准确性。没有经过大量测试。
private static string DoubleToLongString(double x)
{
int shift = (int)Math.Log10(x);
if (Math.Abs(shift) <= 2)
{
return x.ToString();
}
if (shift < 0)
{
double y = x * Math.Pow(10, -shift);
return "0.".PadRight(-shift + 2, '0') + y.ToString().Substring(2);
}
else
{
double y = x * Math.Pow(10, 2 - shift);
return y + "".PadRight(shift - 2, '0');
}
}
Edit: If the decimal point crosses non-zero part of the number, this algorithm will fail miserably. I tried for simple and went too far.
编辑:如果小数点与数字的非零部分交叉,则该算法将失败。我尝试简单但走得太远了。
回答by manji
try this one:
试试这个:
public static string DoubleToFullString(double value,
NumberFormatInfo formatInfo)
{
string[] valueExpSplit;
string result, decimalSeparator;
int indexOfDecimalSeparator, exp;
valueExpSplit = value.ToString("r", formatInfo)
.ToUpper()
.Split(new char[] { 'E' });
if (valueExpSplit.Length > 1)
{
result = valueExpSplit[0];
exp = int.Parse(valueExpSplit[1]);
decimalSeparator = formatInfo.NumberDecimalSeparator;
if ((indexOfDecimalSeparator
= valueExpSplit[0].IndexOf(decimalSeparator)) > -1)
{
exp -= (result.Length - indexOfDecimalSeparator - 1);
result = result.Replace(decimalSeparator, "");
}
if (exp >= 0) result += new string('0', Math.Abs(exp));
else
{
exp = Math.Abs(exp);
if (exp >= result.Length)
{
result = "0." + new string('0', exp - result.Length)
+ result;
}
else
{
result = result.Insert(result.Length - exp, decimalSeparator);
}
}
}
else result = valueExpSplit[0];
return result;
}
回答by Paul Sasik
This is a string parsing solution where the source number (double) is converted into a string and parsed into its constituent components. It is then reassembled by rules into the full-length numeric representation. It also accounts for locale as requested.
这是一个字符串解析解决方案,其中将源编号(双精度)转换为字符串并解析为其组成部分。然后通过规则将其重新组装成全长数字表示。它还根据要求考虑语言环境。
Update: The tests of the conversions only include single-digit whole numbers, which is the norm, but the algorithm also works for something like: 239483.340901e-20
更新:转换测试仅包括个位数整数,这是常态,但该算法也适用于:239483.340901e-20
using System;
using System.Text;
using System.Globalization;
using System.Threading;
public class MyClass
{
public static void Main()
{
Console.WriteLine(ToLongString(1.23e-2));
Console.WriteLine(ToLongString(1.234e-5)); // 0.00010234
Console.WriteLine(ToLongString(1.2345E-10)); // 0.00000001002345
Console.WriteLine(ToLongString(1.23456E-20)); // 0.00000000000000000100023456
Console.WriteLine(ToLongString(5E-20));
Console.WriteLine("");
Console.WriteLine(ToLongString(1.23E+2)); // 123
Console.WriteLine(ToLongString(1.234e5)); // 1023400
Console.WriteLine(ToLongString(1.2345E10)); // 1002345000000
Console.WriteLine(ToLongString(-7.576E-05)); // -0.00007576
Console.WriteLine(ToLongString(1.23456e20));
Console.WriteLine(ToLongString(5e+20));
Console.WriteLine("");
Console.WriteLine(ToLongString(9.1093822E-31)); // mass of an electron
Console.WriteLine(ToLongString(5.9736e24)); // mass of the earth
Console.ReadLine();
}
private static string ToLongString(double input)
{
string strOrig = input.ToString();
string str = strOrig.ToUpper();
// if string representation was collapsed from scientific notation, just return it:
if (!str.Contains("E")) return strOrig;
bool negativeNumber = false;
if (str[0] == '-')
{
str = str.Remove(0, 1);
negativeNumber = true;
}
string sep = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
char decSeparator = sep.ToCharArray()[0];
string[] exponentParts = str.Split('E');
string[] decimalParts = exponentParts[0].Split(decSeparator);
// fix missing decimal point:
if (decimalParts.Length==1) decimalParts = new string[]{exponentParts[0],"0"};
int exponentValue = int.Parse(exponentParts[1]);
string newNumber = decimalParts[0] + decimalParts[1];
string result;
if (exponentValue > 0)
{
result =
newNumber +
GetZeros(exponentValue - decimalParts[1].Length);
}
else // negative exponent
{
result =
"0" +
decSeparator +
GetZeros(exponentValue + decimalParts[0].Length) +
newNumber;
result = result.TrimEnd('0');
}
if (negativeNumber)
result = "-" + result;
return result;
}
private static string GetZeros(int zeroCount)
{
if (zeroCount < 0)
zeroCount = Math.Abs(zeroCount);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < zeroCount; i++) sb.Append("0");
return sb.ToString();
}
}
回答by Letterman
Being millions of programmers world wide, it's always a good practice to try search if someone has bumped into your problem already. Sometimes there's solutions are garbage, which means it's time to write your own, and sometimes there are great, such as the following:
作为全球数以百万计的程序员,如果有人已经遇到您的问题,尝试搜索总是一个好习惯。有时有解决方案是垃圾,这意味着是时候自己写了,有时也很棒,例如以下:
http://www.yoda.arachsys.com/csharp/DoubleConverter.cs
http://www.yoda.arachsys.com/csharp/DoubleConverter.cs
(details: http://www.yoda.arachsys.com/csharp/floatingpoint.html)
(详情:http: //www.yoda.arachsys.com/csharp/floatingpoint.html)
回答by mohamed abdo
i think you need only to use IFormat with
我认为你只需要使用 IFormat
ToString(doubleVar, System.Globalization.NumberStyles.Number)
example:
例子:
double d = double.MaxValue;
string s = d.ToString(d, System.Globalization.NumberStyles.Number);
回答by Robert Lamm
I had a similar problem and this worked for me:
我有一个类似的问题,这对我有用:
doubleValue.ToString("F99").TrimEnd('0')
F99 may be overkill, but you get the idea.
F99 可能有点矫枉过正,但你懂的。