大值 Int 场景下 高效精确 求绝对值 解决方案 ! 「建议收藏」

大值 int 场景下高效精确求绝对值

本文提供 大值 int 类型求绝对值,高效且精确 的一种解决方案!

Math.Abs

  业务逻辑中,对数据取绝对值的操作很常见,各类开发语言都提供了对应的 Math 包,支持 Abs() 函数处理。
  但在一些特殊的场景中,标配的 Abs() 确并不适用!

  下面以 Goland 为例,提供最佳的绝对值解决方案。

数据精度不允许丢失

特殊场景

  在设计 AbTest 平台时,通过 xxhash 对数据进行关系映射,某些情况会映射到 int64 类型的负值「 对应 Java 中 long 类型」,在进行取模的过程需要保证结果为正数,即无符号类型,这样才能正确命中 bit 分桶

  Goland 中标配的绝对值解决方案是 “math” 包的 math.Abs(x float64) 。

不适用问题原因

  首先,我们场景中的目标数据是 int64 , math 包参数为 float64,需要进行转换。在转的过程中,数据过大,数据精度会丢失,无法保证最终分桶的正确性!

  Int 转 float 会出现数据精度丢失的问题,和其各自的存储机制有关。

  - Float 浮点数,内部存储分布为,1 个符号位、8 个指数位、23个小数位。 「以 32 位为例」
  - Int 整形,内部存储为二进制补码。「以 32 位为例」
  - Float 的 23 小数位决定了其表示的精度,当 int 值超过 2^23 时,float 将无法表示,即出现数据精度丢失的问题。

解决方案

  当然,针对这种对数据精确度要求高的场景,各开发语言也提供了额外的包进行支持,如 Goland 中的 Float.SetInt、Java 中的 BigDecimal 等等。

  这里针对特殊数据取绝对值的场景,提出更快,更简洁的解决方案!

位运算高效准确取绝对值

  在一些面试编程题中,我们会接触到数据的 位运算,这里就用其中的 “ 异或 “ 进行实操演示。

异或运算

a⊕b = (¬a ∧ b) ∨ (a ∧¬b)
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

绝对值

func abs(n int64) int64 {
    y := n >> 63
    return (n ^ y) - y
}

注解
若 n 为正数,n >> 63 等于 0 ;
若 n 为负数,n >> 63 等于 -1 ;
若 n 为正数,n^0 = n 数不变 ;
若 n 为负数,有 n^-1 需要计算 n 和 -1 的补码,然后进行异或运算,结果 n 变符号并且为 n 的绝对值减 1 ,再减去 -1 就是绝对值。

举例【32位】
n = 1 , 原码 = 反码 = 补码 = 0000 0001,n >> 31 = 0 , 1^0 = 1 , 1 - 0 = 1;
n = -2 ,源码 = 1000 0010 ,反码 = 1111 1101 ,补码 =1111 1110,n >> 31 = -1,-2^-1 = 1,1-(-1)= 2。

注:
正数,原码 = 反码 = 补码 ;
负数,补码 = 反码 + 1 / 反码 = 原码 除符号位外,取反

Q&A

1、好像没详细介绍 int 转 float 过程?

转换过程涉及各自存储结构,为行业基础内容,本文以提供 “ 大值 int 场景下高效精确求绝对值 的解决方案 ” 为重点。

2、^ 的过程有吗?

-2 ^ -1 ;补码异或为:1111 1110 ^ 1111 1111 = 0000 0001 ,即 1 的补码。

附录

有的时候,在资本规则下,努力没有意义,躺平安好!

欢迎加入Q群聊【编程技术交流分享群717647116】,微信群请私信博主添加

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魏小言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值