双重string转换没有科学记数法

如何在.NET Framework中将double转换为浮点string表示forms而不使用科学记数法?

“小”样本(有效数字可以是任意大小,例如1.5E2001e-200 ):

 3248971234698200000000000000000000000000000000 0.00000000000000000000000000000000000023897356978234562 

没有一个标准的数字格式是这样的, 自定义格式似乎也不允许在小数点分隔符后有一个开放的数字位数。

这不是一个重复的如何将二重string转换为string(E-05),因为这里给出的答案并不能解决问题。 在这个问题上接受的解决scheme是使用一个固定的点(如20位数),这不是我想要的。 格式化和修剪冗余0的固定点无法解决问题,因为固定宽度的最大宽度是99个字符。

注意:解决scheme必须正确处理自定义数字格式(例如其他小数点分隔符,取决于文化信息)。

编辑:这个问题实际上只是关于取代上述数字。 我知道浮点数是如何工作的,可以用什么数字来计算。

对于一个无损的通用解决scheme,您需要保留339个位置:

doubleValue.ToString("0." + new string('#', 339))

非零十进制数字的最大数量为16. 15位于小数点右侧。 指数可以将这15个数字最多移动324个位置。 ( 查看范围和精度。 )

它适用于double.Epsilondouble.MinValuedouble.MaxValue ,以及其中的任何东西。

性能将比正则expression式/string操作解决scheme要大得多,因为所有的格式化和string工作都是由非托pipeCLR代码完成的。 而且,代码要简单得多,certificate是正确的。

为了便于使用,甚至更好的性能,使其成为一个常数:

 public static class FormatStrings { public const string DoubleFixedPoint = "0.###################################################################################################################################################################################################################################################################################################################################################"; } 

我有一个类似的问题,这对我工作:

 doubleValue.ToString("F99").TrimEnd("0".ToCharArray()) 

F99可能是矫枉过正,但你明白了。

这是一个stringparsing解决scheme,源代码(double)被转换成一个string并parsing成其组成部分。 然后由规则重新组装成全长数字表示forms。 它也按照请求来说明区域设置。

更新 :转换的testing只包括一位数的整数,这是常态,但algorithm也适用于类似于: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(); } } 

这是我到目前为止,似乎工作,但也许有人有一个更好的解决scheme:

 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)); 

您可以将doubledecimal ,然后执行ToString()

 (0.000000005).ToString() // 5E-09 ((decimal)(0.000000005)).ToString() // 0,000000005 

我还没有做更快的性能testing,从64位double到128位decimal或300字符以上的格式string。 哦,在转换过程中可能会出现溢出错误,但是如果您的值符合decimal则应该可以正常工作。

更新:演员似乎要快得多。 使用另一个答案中给出的准备好的格式string,格式化一百万次需要2.3秒,而只需要0.19秒。 重复。 这快了10倍 。 现在只是值的范围。

在过去,我们必须编写自己的格式化程序,我们要隔离尾数和指数,并分别格式化它们。

在Jon Skeet( http://www.yoda.arachsys.com/csharp/floatingpoint.html )的这篇文章中,他提供了一个到他的DoubleConverter.cs例程的链接,该链接应该完全按照你想要的来做。 Skeet也提到了在c#中从double中提取尾数和指数 。

强制性的基于对数的解决scheme。 请注意,这个解决scheme,因为它涉及到math,可能会降低你的号码的准确性一点点。 没有严格testing。

 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'); } } 

编辑: 如果小数点越过数字的非零部分,该algorithm将失败。 我尝试了简单,走得太远了。

我刚刚就上面的代码进行了即兴创作,使其适用于负指数值。

 using System; using System.Text.RegularExpressions; using System.IO; using System.Text; using System.Threading; namespace ConvertNumbersInScientificNotationToPlainNumbers { class Program { private static string ToLongString(double input) { string str = input.ToString(System.Globalization.CultureInfo.InvariantCulture); // if string representation was collapsed from scientific notation, just return it: if (!str.Contains("E")) return str; var positive = true; if (input < 0) { positive = false; } 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].Replace("-", ""). Replace("+", "") + decimalParts[1]; string result; if (exponentValue > 0) { if (positive) result = newNumber + GetZeros(exponentValue - decimalParts[1].Length); else result = "-" + newNumber + GetZeros(exponentValue - decimalParts[1].Length); } else // negative exponent { if (positive) result = "0" + decSeparator + GetZeros(exponentValue + decimalParts[0].Replace("-", ""). Replace("+", "").Length) + newNumber; else result = "-0" + decSeparator + GetZeros(exponentValue + decimalParts[0].Replace("-", ""). Replace("+", "").Length) + newNumber; result = result.TrimEnd('0'); } float temp = 0.00F; if (float.TryParse(result, out temp)) { return result; } throw new Exception(); } 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(); } public static void Main(string[] args) { //Get Input Directory. Console.WriteLine(@"Enter the Input Directory"); var readLine = Console.ReadLine(); if (readLine == null) { Console.WriteLine(@"Enter the input path properly."); return; } var pathToInputDirectory = readLine.Trim(); //Get Output Directory. Console.WriteLine(@"Enter the Output Directory"); readLine = Console.ReadLine(); if (readLine == null) { Console.WriteLine(@"Enter the output path properly."); return; } var pathToOutputDirectory = readLine.Trim(); //Get Delimiter. Console.WriteLine("Enter the delimiter;"); var columnDelimiter = (char)Console.Read(); //Loop over all files in the directory. foreach (var inputFileName in Directory.GetFiles(pathToInputDirectory)) { var outputFileWithouthNumbersInScientificNotation = string.Empty; Console.WriteLine("Started operation on File : " + inputFileName); if (File.Exists(inputFileName)) { // Read the file using (var file = new StreamReader(inputFileName)) { string line; while ((line = file.ReadLine()) != null) { String[] columns = line.Split(columnDelimiter); var duplicateLine = string.Empty; int lengthOfColumns = columns.Length; int counter = 1; foreach (var column in columns) { var columnDuplicate = column; try { if (Regex.IsMatch(columnDuplicate.Trim(), @"^[+-]?[0-9]+(\.[0-9]+)?[E]([+-]?[0-9]+)$", RegexOptions.IgnoreCase)) { Console.WriteLine("Regular expression matched for this :" + column); columnDuplicate = ToLongString(Double.Parse (column, System.Globalization.NumberStyles.Float)); Console.WriteLine("Converted this no in scientific notation " + "" + column + " to this number " + columnDuplicate); } } catch (Exception) { } duplicateLine = duplicateLine + columnDuplicate; if (counter != lengthOfColumns) { duplicateLine = duplicateLine + columnDelimiter.ToString(); } counter++; } duplicateLine = duplicateLine + Environment.NewLine; outputFileWithouthNumbersInScientificNotation = outputFileWithouthNumbersInScientificNotation + duplicateLine; } file.Close(); } var outputFilePathWithoutNumbersInScientificNotation = Path.Combine(pathToOutputDirectory, Path.GetFileName(inputFileName)); //Create Directory If it does not exist. if (!Directory.Exists(pathToOutputDirectory)) Directory.CreateDirectory(pathToOutputDirectory); using (var outputFile = new StreamWriter(outputFilePathWithoutNumbersInScientificNotation)) { outputFile.Write(outputFileWithouthNumbersInScientificNotation); outputFile.Close(); } Console.WriteLine("The transformed file is here :" + outputFilePathWithoutNumbersInScientificNotation); } } } } } 

此代码需要一个input目录,并基于分隔符将科学记数法中的所有值转换为数字格式。

谢谢

 string strdScaleFactor = dScaleFactor.ToString(); // where dScaleFactor = 3.531467E-05 decimal decimalScaleFactor = Decimal.Parse(strdScaleFactor, System.Globalization.NumberStyles.Float); 

我可能是错的,但不是这样吗?

 data.ToString("n"); 

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

只要build立在jcasso上说什么你可以做的是通过改变指数来调整你的double值,这样你最喜欢的格式就可以为你做,应用格式,并且用零填充结果来补偿调整。

试试这个:

 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; } 

作为世界各地的数百万程序员,如果有人已经碰到你的问题,那么尝试search总是一个好习惯。 有时候,解决scheme是垃圾,这意味着是时候编写自己的,有时还有很多,比如:

http://www.yoda.arachsys.com/csharp/DoubleConverter.cs

(详情: http : //www.yoda.arachsys.com/csharp/floatingpoint.html )

我想你只需要使用IFormat

 ToString(doubleVar, System.Globalization.NumberStyles.Number) 

例:

 double d = double.MaxValue; string s = d.ToString(d, System.Globalization.NumberStyles.Number); 

我的解决scheme是使用自定义格式。 尝试这个:

 double d; d = 1234.12341234; d.ToString("#########0.#########"); 

这对我来说很好…

 double number = 1.5E+200; string s = number.ToString("#"); //Output: "150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"