![]() | 1 rrfeng 2024-09-28 16:46:15 +08:00 via Android ![]() 基础没学好,回去重修。 --- 解决方法就是钱永远别用小数。 |
![]() | 2 AoEiuV020JP 2024-09-28 16:50:16 +08:00 ![]() 第一反应精度丢失问题,转念想怎么会差这么多, 仔细一看,ceil ,你确定这不是设计如此有人贪这差值吗, |
![]() | 3 Coelacanthus 2024-09-28 16:51:23 +08:00 计算金融不要用二进制浮点数,二进制浮点数的设计就没法精确表示十进制有理数。用十进制浮点数或者定点数,因为金融业务很少用到分以下,用定点数的比较多。十进制浮点数的支持状态也不太好。 |
![]() | 4 TomVista 2024-09-28 16:53:50 +08:00 biginit |
![]() | 5 icyalala 2024-09-28 17:09:17 +08:00 ![]() "1.1" 是十进制,当这个值转为数字的时候是无限循环小数 1.0001100110011001100110011... 舍入后就是 1.0001100110011001100110011001100110011001100110011010, 注意最后一位是向上舍入的。 所以最开始从 "1.1" 这个字符串解析到数字的时候就已经不准确了。 属实是计算机基础不扎实。 |
6 pinocc012 2024-09-28 17:22:14 +08:00 内部数据应该用分为单位的整数吧,显示的时候转换 |
7 c8c 2024-09-28 17:23:39 +08:00 `npm install decimal.js` |
![]() | 8 xiangyuecn 2024-09-28 18:05:17 +08:00 ![]() |
9 chobitssp 2024-09-28 18:06:21 +08:00 bignumber.js |
![]() | 10 cmdOptionKana 2024-09-28 18:15:39 +08:00 凡是涉及金额,都不能简单计算。 一个金额,一个日期,这两个是很典型新手误区,表面上看起来没什么,实际上都藏着大坑。 |
11 haolongsun 2024-09-28 18:29:34 +08:00 金额永远别用浮点数 用 decimal |
12 haolongsun 2024-09-28 18:34:00 +08:00 二进制只能近似存储小数,详细重新学习 IEEE754 ,还有以前面试区分培训和科班第一个就让说 IEEE754 ,不知道的一定是培训出来的,因为培训班不会说什么浮点数底层怎么实现,而是会说金额不让用 double ,科班必定知道,计组第一章就是吧 |
![]() | 13 importmeta 2024-09-28 18:41:07 +08:00 只用数据库计算 |
14 fiveStarLaoliang 2024-09-28 18:44:48 +08:00 string 或者整形存储,计算时得注意精度丢失问题 |
15 iOCZS 2024-09-28 18:58:48 +08:00 ![]() " JS 这个逆天设计",很野的说法 |
![]() | 16 msg7086 2024-09-28 19:06:35 +08:00 ![]() 与其说语言的逆天设计,不如说只知道给金额用浮点数的程序员比较逆天吧。 |
![]() | 17 IvanLi127 2024-09-28 19:14:52 +08:00 这个不是常见的面试题么,没见过嘛? 改用 Decimal.js 吧。https://www.npmjs.com/package/decimal.js/v/10.4.3 其他语言也有类似的库,推荐直接用这种方案来做计算。 |
![]() | 18 masterclock 2024-09-28 20:01:40 +08:00 ![]() |
![]() | 19 est 2024-09-28 20:47:36 +08:00 测了下 1.1 * 100 == 110.00000000000001 向上取整所以是 111 没问题啊。。。 问题在于 LZ 你为啥要向上取整啊。。round 不行么。 |
20 drymonfidelia OP @est 因为商品价格 100 美元,税 10%,业务需求是向上取整到整数 |
![]() | 21 AV1 2024-09-28 21:59:02 +08:00 浮点运算你换什么语言都一样。 涉及财务、金融的计算,*不能用浮点数*,要用*定点数*,这应该是程序员的常识、共识。 |
22 ntedshen 2024-09-28 22:05:00 +08:00 ![]() “业务需求是向上取整到整数”? 简单, Math.ceil(Math.round(1.1*10000)/100) 然后下一届码农:md 屎山+1 (狗头 |
23 drymonfidelia OP ![]() @ntedshen 我真的改成了这样 (狗头 |
![]() | 24 mingl0280 2024-09-29 01:30:45 +08:00 涉及钱币为什么要用浮点数? |
![]() | 26 geelaw 2024-09-29 02:11:53 +08:00 via iPhone @drymonfidelia #20 正确的做法是金额存成 cPrice = 10000 美分,税计算为 ((cPrice * 10000 * bpTaxRate - 1) / 10000 + 1) 美分,其中 bpTaxRate 是税率的基点数(万分之几)。这里假设 cPrice 是非负数(销售),处理退款更麻烦。 |
![]() | 27 geelaw 2024-09-29 02:14:11 +08:00 via iPhone |
28 whileFalse 2024-09-29 02:44:55 +08:00 via Android lz 培训班的,鉴定完毕 |
29 lovestudykid 2024-09-29 02:58:07 +08:00 计算机就业状况还是太好了 |
![]() | 30 lithiumii 2024-09-29 07:19:13 +08:00 via Android ceil 是上取整,你就算是不懂浮点数,用四舍五入这个 bug 也会少很多 |
31 lee88688 2024-09-29 08:13:29 +08:00 #22 的做法其实是正确的,不算什么屎山。使用二进制浮点数表示十进制浮点数在一定有效位数下可以认为是正确的,这个有效位数在 64 位浮点数下大概是 12 位。 在这些位数下转换成整数,然后将整数和小数部分取出来做处理完全没问题,楼主只需要写一些注释,后续人理解没问题的。 |
32 lee88688 2024-09-29 08:17:53 +08:00 多说一句,这种是将浮点数进行最终处理和简单时的做法。因为这些误差在累积计算的时候可能会让偏差越来越大,因此计算的时候还是使用浮点数需要做额外的处理,最好还是使用十进制的库计算或者用 bigint 转化为整数计算。 |
![]() | 33 ahu 2024-09-29 09:27:34 +08:00 如 #8 所说,去看看这个网站: location.href = 'http://' + (.1 + .2) + '.com'; |
![]() | 34 Curtion 2024-09-29 09:33:35 +08:00 这是 IEEE754 的问题,金额相关不要用浮点数,要么使用 Decimal ,要么浮点数拆开成两个整数分开存储 |
![]() | 35 mdn 2024-09-29 09:39:18 +08:00 采用 IEEE 754 浮点数运算的标准的语言 都会出现这个问题,包括 Javascript Java Python 等 建议使用数学库进行运算 |
![]() | 36 lyxxxh2 2024-09-29 09:57:46 +08:00 ![]() 你不该说逆天设计,不是找喷吗。 对金额敏感,用数学库,big.js 之类。 |
![]() | 37 wu67 2024-09-29 10:25:53 +08:00 npm install mathjs -S |
![]() | 38 EndlessMemory 2024-09-29 10:26:07 +08:00 0.1+0.2==0.3 ? |
![]() | 39 sastar 2024-09-29 10:43:18 +08:00 判断 0.1+0.2==0.3 的正确用法应该是 abs(0.1+0.2-0.3)<0.000001 ,具体在小数点后多少位取决于你对精度的要求 |
![]() | 40 winglight2016 2024-09-29 11:20:05 +08:00 ![]() 有点不理解 lz 这个代码是前端还是后端?如果是后端,从数据库设计开始就肯定用整数保存金额啊,包括银行也是这样。 如果是前端,那根本就不该去做计税这个操作正确的设计是把用户输入全部发送到后端去计算。 |
41 thtznet 2024-09-30 14:24:29 +08:00 拿 JS 这种前端语言计算金额?还拿去对账?逆天考量。 |
42 zhhbstudio 2024-10-08 16:29:07 +08:00 @xiangyuecn #8 好东西,收藏了,哈哈哈 |