2016-04-15 12 views
8

Mam następujący podwójne obliczenia w Java:Java kalkulacja precyzja podwójna przegrana

double C1 = some value; // It's always an integer 
double C2 = some value; // It's always integer, and C2 >= C1 
double S = some value;  // It's always 0 < S <= 1 
double carry = some value; // It's always 0 <= carry < 1 

double rate = ((C1/C2)/S); 
double C3 = Math.floor((rate * S * C2) + carry); 

Teraz, jeśli nie tracą precyzję, C3 == C1 byłoby prawdziwe. Ale ponieważ tracimy precyzję, czy C3 i C1 wciąż będą równe?

Jeśli one nie zawsze będzie równe, jeśli mam C1, C2, S i C3, jak mogę zmodyfikować rate aby upewnić po obliczeniu C3 byłaby równa C1?

Uwaga: niestety użycie opcji BigDecimal nie jest opcją.

+1

Jeśli chcesz zachować precyzję, użyj "BigDecimal". – SomeJavaGuy

+0

Niestety użycie BigDecimal nie jest opcją, ponieważ tempo jest już zapisane po utracie precyzji i nie mogę nic z tym zrobić. – user1819676

+7

@KevinEsche BigDecimal zapobiega tylko utracie precyzji, jeśli liczby są reprezentowane jako ułamkowe części dziesiętne. Rozważmy przypadek C1 = 1, C2 = 1, S = 0.3 –

Odpowiedz

3

Ogólnie nie porównujemy dwóch podwójnych wartości bezpośrednio przez ==. Zamiast tego mierzymy różnicę między nimi. na przykład Math.abs(C3 - C1) < 1e-6.

+0

Tak, jeśli chodzi o porównywanie podwójnych. Ale funkcja wykonująca Math.floor zwraca liczbę całkowitą. Spójrz na to w ten sposób. 'S' i' C2' są przechowywane w db, a my mamy tę funkcję, która w przyszłości będzie używana do obliczania C3.Teraz chcemy zapisać 'rate' lub jakąś modyfikację' rate' na db, aby zagwarantować, że funkcja wygeneruje 'C3 == C1' – user1819676

3

Nie tak.

Współczynnik zmiennoprzecinkowy jest przybliżeniem. Następne podwójne, bit 1 dodany do mantysy może spowodować dość dużą przerwę dla dużych wykładników pomiędzy tymi dwoma podwójnymi.

S przybliżenie 0 spowoduje ogromne duble, które mają dużą przerwę między nimi. To nie będzie już możliwe do skorygowania, np. Za pomocą tego prostego zaokrąglenia. Nawet jeśli mały S nie spowoduje, że podział przekroczy podwójny zakres z INFINITY.

Można łatwo uzyskać od 1000.