C# float乘1000出现不一致舍入 如何实现无舍入精确计算
这是float(单精度浮点数)的固有精度缺陷导致的,和你乘1000还是1000f没有关系。float是32位二进制浮点数类型,仅能保证6~7位十进制有效数字的精度,大量十进制小数无法被它精确存储。你传入的"4150.8"被解析为float时,实际存储的值略小于真实的4150.8,乘以1000后得到的是类似4150799.9999的结果,而你用(int)强转时会直接截断小数部分,最终就得到了4150799的错误值。至于"2767.3"能返回正确结果只是刚好这个值能被float近似到误差不影响截断结果的程度,属于巧合。
要实现全程无舍入的精确计算,不要用二进制浮点数处理这类十进制精确运算需求,以下两种方案都可以:
方案1:使用decimal类型做运算(推荐)
decimal是C#专门为十进制精确场景设计的128位数据类型,不存在二进制浮点数的精度误差,完全兼容C# 7.3版本,修改后的代码如下:
public static string MapDiePitchY(string DiePitchY) { decimal value = decimal.Parse(DiePitchY) * 1000m; int valInt = (int)value; return valInt.ToString(); }
测试传入"4150.8"会正确返回4150800,"2767.3"也会保持正确的2767300结果。
注意不要用double替换float,double虽然精度更高,但本质还是二进制浮点数,依然存在无法精确表示部分十进制小数的问题,只是触发误差的阈值更高,长期使用还是会出现同类问题。
方案2:直接处理字符串(零数值运算误差)
如果你的输入格式固定为十进制数字字符串,也可以完全绕开数值类型转换,直接操作字符串:找到小数点的位置,将小数点后移3位后删除多余的小数部分即可,这种方式完全不会有数值运算的精度问题,但是需要提前做好输入格式校验,适合输入格式完全可控的场景。
(int)强转是直接截断小数部分的操作,不存在四舍五入,如果后续你可能传入小数位超过1位的数值,需要提前明确截断规则,避免出现不符合预期的结果。
内容的提问来源于stack exchange,提问作者devn00b1090

