阿里P8级架构师怎么处理电商业务中的数值计算的精度/舍入/溢出问题?(下)

简介: 阿里P8级架构师怎么处理电商业务中的数值计算的精度/舍入/溢出问题?

4 浮点数的舍入和格式化

应考虑显式编码,通过格式化表达式或格式化工具

4.1 明确小数位数舍入方式

  • 通过String.format使用%.1f格式化double/float的3.35浮点数
  • image.png
  • 结果
    3.4和3.3

精度问题和舍入方式共同导致:double/float的3.35实际存储表示

3.350000000000000088817841970012523233890533447265625
3.349999904632568359375

String.format采用四舍五入的方式进行舍入,取1位小数,double的3.350四舍五入为3.4,而float的3.349四舍五入为3.3。

我们看一下Formatter类的相关源码,可以发现使用的舍入模式是HALF_UP(代码第11行):

image.png

若想使用其他舍入方式,可设置DecimalFormat

image.png

当把这俩浮点数向下舍入取2位小数时,输出分别是3.35、3.34,还是因为浮点数无法精确存储。


所以即使通过DecimalFormat精确控制舍入方式,double/float也可能产生奇怪结果,所以


4.2 字符串格式化也要使用BigDecimal

  • BigDecimal分别使用向下舍入、四舍五入取1位小数格式化数字3.35
  • image.png
  • 结果
    3.3和3.4,符合预期。

最佳实践:应该使用BigDecimal来进行浮点数的表示、计算、格式化。

5 equals做判等就一定对?

包装类的比较要通过equals,而非==。那使用equals对两个BigDecimal判等,一定符合预期吗?

  • 使用equals比较1.0和1这俩BigDecimal:
  • image.png
  • 结果自然是false。BigDecimal的equals比较的是BigDecimal的valuescale:1.0的scale是1,1的scale是0,所以结果false
  • image.png
  • 若只想比较BigDecimal的value,使用compareto
  • image.png
  • BigDecimal的equalshashCode会同时考虑valuescale,若结合HashSet/HashMap可能出问题。把值为1.0的BigDecimal加入HashSet,然后判断其是否存在值为1的BigDecimal,得到false
  • image.png

5.1 解决方案

5.1.1 使用TreeSet替换HashSet

TreeSet不使用hashCode,也不使用equals比较元素,而使用compareTo方法。

image.png

5.1.2 去掉尾部的零

把BigDecimal存入HashSet或HashMap前,先使用stripTrailingZeros方法去掉尾部的零。

比较的时候也去掉尾部的0,确保value相同的BigDecimal,scale也是一致的:

image.png

6 溢出问题

所有的基本数值类型都有超出保存范围可能性。

  • 对Long最大值+1
  • image.png
  • 结果是一个负数,Long的最大值+1变为了Long的最小值
    -9223372036854775808

显然发生溢出还没抛任何异常。

6.1 解决方案

6.1.1 使用Math类的xxExact进行数值运算

这些方法会在数值溢出时主动抛异常。

image.png

执行后,会得到ArithmeticException,这是一个RuntimeException:

java.lang.ArithmeticException: long overflow

6.1.2 使用大数类BigInteger

BigDecimal专于处理浮点数的专家,而BigInteger则专于大数的科学计算。


使用BigInteger对Long最大值进行+1操作。若想把计算结果转为Long变量,可使用BigInteger#longValueExact,在转换出现溢出时,同样会抛出ArithmeticException

image.png

  • 结果
9223372036854775808
java.lang.ArithmeticException: BigInteger out of long range

通过BigInteger对Long的最大值加1无问题,但将结果转为Long时,则会提示溢出。

参考

目录
相关文章
|
4月前
|
监控
阿里商旅账单系统架构设计实践问题之对账模型包括内容问题如何解决
阿里商旅账单系统架构设计实践问题之对账模型包括内容问题如何解决
|
1月前
|
消息中间件 缓存 Java
亿级流量电商平台微服务架构详解
【10月更文挑战第2天】构建一个能够处理亿级流量的电商平台微服务架构是一个庞大且复杂的任务,这通常涉及到多个微服务、数据库分库分表、缓存策略、消息队列、负载均衡、熔断降级、分布式事务等一系列高级技术和架构模式。
91 3
|
4月前
|
消息中间件 负载均衡 数据管理
微服务架构在电商平台中的应用与实践
在现代电商平台的开发和运维中,微服务架构成为了提升系统灵活性和可扩展性的关键技术。本篇文章从实践出发,深入探讨了微服务架构在电商平台中的具体应用,包括服务拆分策略、通信机制、数据管理、以及常见的挑战和解决方案。通过真实的案例分析和代码示例,帮助读者全面了解微服务架构的优势和实施方法,提供在实际项目中的实践指导。
|
4月前
|
数据格式
阿里商旅账单系统架构设计实践问题之系统设计中的清结算系统问题如何解决
阿里商旅账单系统架构设计实践问题之系统设计中的清结算系统问题如何解决
|
5月前
|
安全 前端开发 Java
Spring Boot导购电商返利App架构设计
Spring Boot导购电商返利App架构设计
|
5月前
|
负载均衡 监控 UED
高可用电商返利APP架构设计与实现分享
高可用电商返利APP架构设计与实现分享
|
4月前
|
搜索推荐 Java
阿里商旅账单系统架构设计实践问题之需要账单数据表达式引擎问题如何解决
阿里商旅账单系统架构设计实践问题之需要账单数据表达式引擎问题如何解决
|
4月前
|
监控 供应链 搜索推荐
阿里商旅账单系统架构设计实践问题之账单详情数据未同步会带来问题如何解决
阿里商旅账单系统架构设计实践问题之 账单详情数据未同步会带来问题如何解决
|
4月前
|
存储 搜索推荐
阿里商旅账单系统架构设计实践问题之差错处理(平账)的主要目的问题如何解决
阿里商旅账单系统架构设计实践问题之差错处理(平账)的主要目的问题如何解决
|
5月前
|
消息中间件 缓存 Java
高性能电商返利APP架构设计与实现
高性能电商返利APP架构设计与实现
下一篇
无影云桌面