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

Math 如何手动将双精度(浮点)乘以整数类型(32位、64位、128位等),math,floating-point,double,Math,Floating Point,Double,我试图手动实现一个double和一个128位整数之间的乘法,我自己用两个ulong创建了这个整数 我的理解如下: 1.将双精度分解为其有效位和指数。确保有效位为。 2.将有效位与我的uint128相乘。这将给我256位的数字。 3.将我的256位数字按从double中提取的指数进行移位。 4.如果值超过128位,则I溢出 我觉得我离得很近,但我错过了一些东西。假设我有下面的例子。我正在存储一个值为2^127的uint128,我想将其乘以8E-6 uint128 myValue = new uin

我试图手动实现一个double和一个128位整数之间的乘法,我自己用两个ulong创建了这个整数

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

我觉得我离得很近,但我错过了一些东西。假设我有下面的例子。我正在存储一个值为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
我使用来自的代码来获取尾数和指数。我可以使用这些值正确地将8E-6作为双精度返回

有人知道我这里出了什么问题吗?如果我使用.8而不是8E-6,我的值会更好

我这里做错了什么

双乘数
的算术值不为0.000008。它的小数点位接近0.000008至15-17位。这种差异导致没有达到您的期望

1234567890123456
1361129467683753 853853498429727072.845824 - perceived product
1361129467683753 853853498429727072        - perceived rounded product
1361129467683753 792259819967610881        - product seen.
尝试使用小数形式的精确值,如0.0625(1.0/16),使用乘法器


注:

使用时,最接近8E-6的
double
为() 0.000007999999999999999637984894607090069484911509789526462554931640625.

将其乘以2127正好是

1361129467683753 792259819967610880.0

所以乘法看起来是一,可能是四舍五入?

您在这里展示的是什么编程语言?C#是我写它的语言,但只要使用IEEE 754浮点双精度,这种语言就不太相关。我写了我自己的UInt128,我自己的乘法处理256位,以及double的分解。回过头来看,我知道你已经有了一个数据类型,可以得到你想要的结果,System.Decimal,但是你希望得到更好的性能。通常,在硬件实现和软件实现之间需要迈出一大步。你确定你将获得足够的绩效提升来证明这项工作的合理性吗?@PatriciaShanahan我不是。System.Double的性能明显快于System.Decimal,但System.Double可能不足以满足我所需的精度。我正在研究一组特定值范围内的特定操作。我想最终,我不会更快,但我需要有有效的代码来进行基准测试,以便自信地展示这一点。所以有一些值,比如0.8,正如我所预料的那样。有没有一种方法可以处理没有算术值的双精度码,如果有,有没有一种方法可以判断双精度码是否有算术值?@ChrisDelpire唯一没有算术值的双精度码是无穷大和NaNs(所有位都是一个指数)。问题恰恰相反。有许多小数点与任何double都不完全对应,因此它们在小数点到double的转换中得到近似值。@PatriciaShanahan这是否意味着当我存储8E-6时,它实际上是在引擎盖下存储7.9999999E-6?例如,在C#中,当我查看值时,它是如何显示为8E-6的?与8E-6最接近的IEEE 754 64位二进制数是0.00000079999999999999996379848946070900694849115097895264625491640625。大多数语言设计师觉得程序员不想看到这样的东西,所以他们会缩短并取整输出。@ChrisDelpire要得到136…072,你需要将
2^127
乘以
double
以外的东西,我怀疑
long double
是否足够。因此,问题变成了使用什么类型/结构来表示
8E-6