如何手动将 double(浮点数)乘以整数类型(32 位、64 位、128 位等)

How to multiply double (floating point) by an integer type (32-bit, 64-bit, 128-bit, etc.) manually

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

我的理解如下:
1. 将 double 分解为它的有效数和指数。确保有效数是 normalized.
2. 将有效数字与我的 uint128 相乘。这将给我 256 位数。
3. 将我的 256 位数字按从 double 中提取的指数移动。
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

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

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

what I am getting wrong here?

double multiplier 没有算术值 0.000008。它有一个 dyadic value near 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, the closest double to 8E-6 is () 0.000007999999999999999637984894607090069484911509789526462554931640625。

乘以 2127 正好是

1361129467683753 792259819967610880.0

所以乘法看起来是差一,也许是四舍五入?