首页 > 解决方案 > 如何手动将双精度(浮点数)乘以整数类型(32 位、64 位、128 位等)

问题描述

我正在尝试手动实现我使用两个 ulong 创建自己的双精度和 128 位整数之间的乘法。

我的理解如下:
1.将双精度数分解为有效数和指数。确保有效数字归一化
2. 将有效数字与我的 uint128 相乘。这将给我 256 位数。
3. 将我的 256 位数按从双精度中提取的指数移位。
4.如果值超过128位,那么我溢出了。

我觉得我非常接近,但我错过了一些东西。可以说我有以下示例。我正在存储一个值为 2^127 的 uint128,我想将它乘以 8E-6。

uint128 myValue = new uint128(2^127);
double multiplier = 8E-6;
uint128 product = myValue * multiplier;

真正的价值或正确答案是1361129467683753853853498429727072.845824。所以我想把这个值1361129467683753853853498429727072作为我的 128 位整数。

问题是我的实现给了我1361129467683753792259819967610881.

int exponent; // This value ends up being -69 for 8E-6
uint128 mantissa = GetMantissa(multiplier, out exponent); // This value ends up being 4722366482869645 after normalizing it.
uint256 productTemp = myValue * mantissa; // This value is something like 803469022129495101412490705402148357126451442021826560.
uint128 product = productTemp >> exponent. // this value is 1361129467683753792259819967610881

我正在使用从c# 中的 double 中提取尾数和指数的代码来获取我的尾数和指数。我可以使用这些值正确地将 8E-6 作为双精度值返回。

有谁知道我在这里做错了什么?如果我使用 .8 而不是 8E-6,我的值会更好。

标签: mathfloating-pointdouble

解决方案


我在这里做错了什么?

double multiplier没有 0.000008 的算术值。它的二进值 接近0.000008,到 15-17 位有效小数位。这种差异导致不符合您的期望。

1234567890123456
1361129467683753 853853498429727072.845824 - perceived product
1361129467683753 853853498429727072        - perceived rounded product
1361129467683753 792259819967610881        - product seen.

尝试multiplier使用精确的十进制值,例如 0.0625 (1.0/16)。


笔记:

使用binary64,最接近double8E-6 的是 ( @Patricia Shanahan ) 0.000007999999999999999637984894607090069484911509789526462554931640625。

乘以 2 127正好是

1361129467683753 792259819967610880.0

所以乘法似乎是一倍的,也许是四舍五入?


推荐阅读