我想将一个高精度整数(long或BigInteger)乘以一个小的double(考虑一些> 0和<1),并获得操作的精确算术值的算术舍入整数(long或BigInteger)作为结果 .
将double转换为整数不起作用,因为它的小数值会丢失 .
将整数转换为double,然后乘以并将结果转换回整数也不起作用,因为double不够精确 . 当然你可以争辩说,因为双操作数首先不够精确,所以结果在数量级上不精确可能并不重要,但在这种情况下,确实如此 .
奖金问题:
使用BigDecimal工作,但似乎效率很低 . 将long转换为double然后再乘以转换回来似乎比转换为BigDecimal快500倍(尽管精度下降) . 有更有效的可能性吗?是否有可能在将几个不同的长度乘以相同的双倍时获得性能?
4 回答
您想使用BigDecimal以保持精度 .
使用BigDecimal确实有效 . 您仍然必须小心使用double表示的精确值并进行算术舍入 .
输出:
我能看到的最佳解决方案是使用Math.round函数 . 用这样的代码 .
这将为您提供答案而不会丢失预防错误 . 另一种选择是截断它 .
与上述代码相同 .
Double有52位的精确度 . 怎么样:
乘以你的双倍(1 << 52)
将double转换为BigInteger(小数点左边的全精度没有损失)
与其他BigIngeger相乘
部分正确的结果二进制指数(BigInteger >> 51)
如果很奇怪,可以通过添加1或BigInteger.Sign进行舍入(取决于您的舍入偏好)
最后移位一位(BigInteger >> 1)
BigInteger myBI = BigInteger("99999999999999999");
双d = 0.123;
BigInteger bigDouble =(BigInteger)(d *((ulong)1 << 52));
BigInteger结果=(myBI * bigDouble)>> 51; if(!result.IsEven)
result = result.Sign; result =结果>> 1;