【问题标题】:float invalid conversion / float unexpected behavior浮动无效转换/浮动意外行为
【发布时间】:2018-11-22 10:55:37
【问题描述】:

我正在尝试不考虑浮动行为(在 C# 中)。我注意到了floating point precision issue 的东西。 我想将浮点字符串转换为浮点数,向其添加 + 1 并将其转换回字符串。输入可以带(不超过 5 位小数)或不带小数,每次都不同。输出必须再次是完整的符号(没有科学记数法,例如:2.017002E+09F)

小数转换似乎可以正常工作。

对使用浮点数的最佳实践有什么建议吗?

var inputDecimalStr = "2017002005"; //2017002005.55 has the same result for the float conversion
float floatRegNr = 0;
float.TryParse(inputDecimalStr, out floatRegNr); // somehow this converts to 2.017002E+09
decimal test1 = decimal.Parse(inputDecimalStr); // this seems to work
float test2 = Convert.ToSingle(test1); // somehow this converts to 2.017002E+09
float test3 = Single.Parse(inputDecimalStr, NumberStyles.Float, CultureInfo.InvariantCulture);
float test4 = 2017002005F;
float test5 = 2.017002E+09F;
float test6 = 2.017002005E+09F;
double test7 = 234423.33D;

//this works ok
test5.ToString("0." + new string('#', 339));
test1.ToString();

【问题讨论】:

  • float 的精度为 7 位有效数字,您可以信赖。 2017002005 有 10 位有效数字 - 所以是的,您将丢失信息,并且在该值上加 1 不会产生任何影响。就科学记数法而言,这仅在您将值转换回字符串时才相关 - 使用“N”标准格式字符串来避免使用科学记数法进行格式化。
  • 从根本上说,如果您关心精确的十进制值,decimal 可能是您更好的选择。如果您不介意精度问题,但需要比float 提供的精度更高,请改用double。不过,doubledecimal 的精度仍然存在限制。这不是小数位数的数量问题,而是有效数字的问题。
  • 嗯,不知道浮点数的7位精度,以为是30+位左右。在这种情况下,这可能是最好的做法。我需要在输入中加 1,所以没有比较。小数点似乎适用于这项工作。谢谢
  • 尾数(“有效数字”)有 23 个(+1,因为省略了数字的第一个 1)。但当然,23 位不会给你 23 个十进制数字。

标签: c# floating-point


【解决方案1】:

如果你使用this tool that shows you the binary representation of float,你会得到2017002005被表示为0x4ef07204,它转换回十进制形式变成2017001984(转换出来的错误是21)。

如果您更改数字的最低有效位(即可以注册的最小更改),您将得到0x4ef07205,它代表2017002112(比2017002005 + 1 多107。

如果这种详细程度很重要,您可以使用定点算法。由于只想加 1,所以将数字分成整数和小数部分,整数部分加 1,然后将每个部分分别转换回 String。

【讨论】:

  • 哇,没想到,拆分后加1再合并到字符串中,不需要浮点逻辑。我认为这样更有效率。谢谢
猜你喜欢
  • 1970-01-01
  • 2012-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
  • 2015-06-01
相关资源
最近更新 更多