大值 Int 场景下 高效精确 求绝对值 解决方案 ! 「建议收藏」
Posted 魏小言
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大值 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】,微信群请私信博主添加
以上是关于大值 Int 场景下 高效精确 求绝对值 解决方案 ! 「建议收藏」的主要内容,如果未能解决你的问题,请参考以下文章