Wprowadzam 64-bitowy stały numerowany 31.32 numeryczny w C#, na podstawie long
. Do tej pory tak dobre dla dodawania i odejmowania. Mnożenie ma jednak irytującą sprawę, którą próbuję rozwiązać.64-bitowy błąd mnożenia stałoprzecinkowego
Mój aktualny algorytm polega na podzieleniu każdego operandu na jego najbardziej i najmniej znaczące 32 bity, wykonaniu 4 multiplikacji na 4 długie i dodaniu odpowiednich bitów tych długich. Tutaj jest w kodzie:
public static Fix64 operator *(Fix64 x, Fix64 y) {
var xl = x.m_rawValue; // underlying long of x
var yl = y.m_rawValue; // underlying long of y
var xlow = xl & 0x00000000FFFFFFFF; // take the 32 lowest bits of x
var xhigh = xl >> 32; // take the 32 highest bits of x
var ylow = yl & 0x00000000FFFFFFFF; // take the 32 lowest bits of y
var yhigh = yl >> 32; // take the 32 highest bits of y
// perform multiplications
var lowlow = xlow * ylow;
var lowhigh = xlow * yhigh;
var highlow = xhigh * ylow;
var highhigh = xhigh * yhigh;
// take the highest bits of lowlow and the lowest of highhigh
var loResult = lowlow >> 32;
var midResult1 = lowhigh;
var midResult2 = highlow;
var hiResult = highhigh << 32;
// add everything together and build result
var finalResult = loResult + midResult1 + midResult2 + hiResult;
return new Fix64(finalResult); // this constructor just copies the parameter into m_rawValue
}
Działa to w ogólnym przypadku, ale kończy się niepowodzeniem w wielu scenariuszach. Mianowicie, wynik jest wyłączony o 1,0 (wartość dziesiętna), często dla bardzo małych lub dużych wartości operandów. Oto niektóre wyniki moich testów jednostkowych (FromRaw() jest metodą, która buduje Fix64 bezpośrednio z dużej wartości, bez przesuwania go):
Failed for FromRaw(-1) * FromRaw(-1): expected 0 but got -1
Failed for FromRaw(-4) * FromRaw(6791302811978701836): expected -1.4726290525868535041809082031 but got -2,4726290525868535041809082031
Failed for FromRaw(2265950765) * FromRaw(17179869183): expected 2.1103311001788824796676635742 but got 1,1103311001788824796676635742
Staram się wypracować z logiką tego na papierze ale trochę utknąłem. Jak mogę to naprawić?
Co robisz z bity do przenoszenia? Ponadto, nie całkiem rozumiem tłumaczenie. Jaka jest odpowiednia wartość liczbowa słowa "2265950765"? – mellamokb
Tak, a co z taśmami transportowymi? –
Nie jestem zaznajomiony z zasadami promocji liczb całkowitych w C# - czy wartości 'lowlow' itp. 32-bitowe, czy też mnożenie 32x32 automatycznie daje wynik 64-bitowy? – hobbs