用浮点数表达十进制中的小数会出现误差, 但是这个误差极小, 基本上计算出来的都是 0.xx00000000xxx 或者 0.xx99999999xxx, 这个时候我们只取小数点后两位应该是很精确地, 我想不到什么时候这样会出问题, 求指教
1
petelin OP 加一个条件, 参加计算的小数,标度最大为 2, 也就是说不会有 0.001 这种
|
2
coderfox 2017-07-07 17:41:07 +08:00 via Android
是要存金钱吗?
位数确定的小数,在不超过数据类型范围的情况下还是建议存成整数。 一方面是肯定不会出现精度损失; 另一方面是整型的计算、序列化、反序列化都比浮点数快。 |
3
choury 2017-07-07 17:42:32 +08:00
直接乘以 100 存成整数多好
|
4
h4x3rotab 2017-07-07 17:56:59 +08:00 via iPhone
原因是浮点表示实际是二进制小数,很多十进制小数在二进制下就是循环小数。资金要用 fixed 表示。
|
5
littleylv 2017-07-07 18:00:39 +08:00
现在一般建议价格等金额的数据存整数
|
6
af463419014 2017-07-07 18:07:36 +08:00
用 decimal,不会出现浮点数计算的误差
|
7
snnn 2017-07-07 18:12:16 +08:00 via Android
看你要做什么操作了。只是加减法就还好
|
8
archer2ee 2017-07-07 18:13:27 +08:00 via iPhone
如果是金钱的话,存分!!我做支付用 bigdecimal 也感觉各种麻烦。float 就是禁区了。
|
9
BigBearWatchYou 2017-07-07 18:52:49 +08:00
你不妨试试 System.out.println(999999.99f);
建议: 1.float 最多保证 7 位有效数字,如果超过了,就不要用 float,而是使用 bigdecimal (这里的有效数字指:从该数高位的第一个非零数字起,直到低位末尾的小数非零数字或个位止的数字) 2.因为 bigdecimal 的性能不好,如果是跟钱有关,只可能有两位小数,那建议直接用 long 存分,在需要显示的地方格式化 |
10
BigBearWatchYou 2017-07-07 18:57:10 +08:00
而且如果要进行四则运算,因为有对阶过程,float 连 7 位有效数字的精度也无法保证
|
11
bear2017 2017-07-07 21:26:30 +08:00 via Android
是涉及到钱吗?涉及钱的话用分做单位,显示客户端统一除 100。不要用 float,会有问题的。
|
12
rrfeng 2017-07-07 21:59:06 +08:00
这个直接 * 100 存整数。
只要是小数,不管你几位总会出现误差的。 |
13
gogohigh 2017-07-07 22:09:04 +08:00
不行。float 只是近似值,用 String 或者*100 存整形
|
14
xenme 2017-07-07 22:21:17 +08:00
歪个楼:
上面好多出现一分钱抢购的是不是都是你们存分,然后计算的时候没有乘以 100,直接卖了啊? |
15
akira 2017-07-07 22:21:35 +08:00
没有问题。
|
16
mingyun 2017-07-07 23:06:32 +08:00
参考微信用分做单位
|
17
zoudm 2017-07-07 23:48:31 +08:00
一个经典样例。
#include <stdio.h> int main() { float t = 0.1; float sum = 0; for (int i = 0; i < 100000; i++) { sum += t; } printf("sum: %f\n", sum); return 0; } gcc -o testfloat testfloat.c ./testfloat sum: 9998.556641 准确结果应该为 10000,实际为 9998.556641 |
18
hjc4869 2017-07-08 00:52:11 +08:00 via Android
问题很大,楼主的需求明显是要用定点数。
|
19
kx5d62Jn1J9MjoXP 2017-07-08 07:59:20 +08:00 via Android
有,较大的数,float 连整数都无法全部覆盖
|
20
chinawrj 2017-07-08 10:24:18 +08:00 via Android
不要用浮点,不要用浮点,不要用浮点!直接倍数之后用整型!或者有金融 math 库
|
21
petelin OP @zoudm 为什么这个误差这么大, 我用 python 实验的时候, `sum(0.1 for i in range(100000))` 结果是 10000.000000018848, 我觉得可以接受啊
|
22
petelin OP 确实是存金额, 老大不让用分.........
|
23
petelin OP @BigBearWatchYou 试了一下是 1000000.0, 这样的话在 java 里肯定不能用了. 现在比较好奇为什么 python 对浮点数处理这么好,
In [29]: Decimal(float(99999.99)) Out[29]: Decimal('99999.990000000005238689482212066650390625') 误差都很小的, 包括上面一位同学给出的 C 代码, 在 python 下精度也很高.我去搜搜 |
24
petelin OP @petelin Python 下浮点数都是用双精度存的,所以精度会高一点, 这个时候 99999999999999.99 就开始不精确了
In [38]: 99999999999999.99 + 99999999999999.99 Out[38]: 199999999999999.97 我觉得如果你的系统任何一处能算到这么大的数, 那就不能用了, 如果没有的还是可以的用的, 0.1d 在怎么加,只要小数点后两位也没什么问题. ps: 都是个人直觉...实际工作还是存分吧, 或者老大说怎么搞就怎么搞 :) |
25
BigBearWatchYou 2017-07-10 21:04:24 +08:00
@petelin IEEE 754 协议规定的,大部分语言里都遵循这个,单精度保证 7 位,双精度保证 15 位
具体计算细节我之前思考过,还挺有意思的。不只是直接 N*lg2,而是整数部分看大小,小数部分看舍入,然后一块计算,但是最后结果也是近似 N*lg2,有空我可以整理一下 |