Sto implementando un tipo numerico 31.32 con segno fisso a 64 bit in C#, basato su long
. Fin qui tutto bene per l'aggiunta e la sottrazione. La moltiplicazione ha tuttavia un caso fastidioso che sto cercando di risolvere.Errore di moltiplicazione a virgola fissa a 64 bit
Il mio algoritmo attuale consiste nel suddividere ciascun operando nei suoi 32 bit più o meno significativi, eseguendo 4 moltiplicazioni in 4 long e aggiungendo i bit rilevanti di questi long. Qui è nel codice:
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
}
Questo funziona nel caso generale, ma non riesce in un numero di scenari. Vale a dire, il risultato è disattivato di 1,0 (valore decimale), spesso per valori estremamente piccoli o grandi degli operandi. Qui ci sono alcuni risultati dal mio test di unità (FromRaw() è un metodo che costruisce una Fix64 direttamente da un lungo valore, senza spostare di esso):
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
Sto cercando di capire la logica di questo su carta ma sono un po 'bloccato. Come posso risolvere questo?
Cosa stai facendo con i bit di trasporto? Inoltre, non sto capendo la traduzione ... qual è il valore numerico equivalente di '2265950765', per esempio? – mellamokb
Sì, per quanto riguarda i bit di trasporto? –
Non ho familiarità con le regole di promozione dei numeri interi di C# - i valori 'lowlow' ecc. 32-bit, o la moltiplicazione 32x32 fornisce automaticamente un risultato a 64-bit? – hobbs