Как умножить double (с плавающей запятой) на целочисленный тип (32-разрядный, 64-разрядный, 128-разрядный и т. Д. c.) Вручную - PullRequest
2 голосов
/ 07 января 2020

Я пытаюсь вручную реализовать умножение между двойным и 128-битным целым числом, которое я создал сам, используя два улонга.

Мое понимание таково:
1. Разложить двойное на его значение и и показатель. Обеспечение значимости и нормализовано .
2. Умножьте значение и мое мнение128. Это даст мне 256-битное число.
3. Сдвиньте мое 256-битное число на экспоненту, извлеченную из двойного.
4. Если значение превышает 128 бит, то я переполнен.

Мне кажется, что я невероятно близок, но что-то упускаю. Допустим, у меня есть следующий пример. Я храню uint128 со значением 2 ^ 127 и хочу умножить его на 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#, чтобы получить мою мантиссу и экспоненту. Я могу использовать эти значения, чтобы правильно вернуть 8E-6 как двойное число.

Кто-нибудь знает, что я здесь ошибаюсь? Если я использую 0,8 вместо 8E-6, мои значения лучше.

1 Ответ

1 голос
/ 07 января 2020

что я тут не так делаю?

double multiplier не имеет арифметического c значения 0,000008. Он имеет значение dyadi c около 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).


Примечания:

С бинарным 64 , ближайшим double к 8E-6 является ( @ Патрисия Шанахан ) 0,000007999999999999999637984894607090069484911509789526462554931640625.

Умножение на 2 127 в точности равно

1361129467683753 792259819967610880.0

Таким образом, умножение выглядит как единичное, возможно округление?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...