podejrzewać, że różnica jest konwersja z 80-bitowej wartości zmiennoprzecinkowej na długi vs konwersji z 80-bitowej wartości zmiennoprzecinkowej na 64-bitowy jednego i następnie konwersję długi.
(Powodem dla 80 bitów wymyślanie w ogóle jest to, że jest to typowy precyzja wykorzystywane do rzeczywistej arytmetyki, a szerokość przestawne rejestrów punktowych.)
Załóżmy, że wynik 80-bit jest coś 10.999999999999999 - w konwersja z tego na długą wydajność 10. Jednak najbliższa 64-bitowa wartość zmiennoprzecinkowa do 80-bitowej wartości wynosi faktycznie 11,0, więc konwersja dwustopniowa kończy się dając 11.
EDYCJA: Aby nadać temu trochę więcej wagi ...
Oto program w języku Java, który wykorzystuje arytmetykę arytmetyki arbitralnej do wykonywania sam e obliczenia. Zwróć uwagę, że konwertuje podwójną wartość najbliższą 0.1 w BigDecimal - ta wartość to 0,1000000000000000055511151231257827021181583404541015625. (Innymi słowy, dokładny wynik obliczeń jest nie 11 anyway.)
import java.math.*;
public class Test
{
public static void main(String[] args)
{
BigDecimal c = new BigDecimal(0.1d);
BigDecimal a = new BigDecimal(1d);
BigDecimal b = new BigDecimal(2d);
BigDecimal result = b.subtract(a)
.add(c)
.divide(c, 40, RoundingMode.FLOOR);
System.out.println(result);
}
}
Oto wynik:
10.9999999999999994448884876874217606030632
Innymi słowy, jest to poprawne do około 40 cyfr po przecinku (droga więcej niż 64 lub 80-bitowy zmiennoprzecinkowy może obsłużyć).
Rozważmy teraz, jak wygląda ten numer w systemie binarnym. Nie mam żadnych narzędzi, które umożliwiałyby łatwą konwersję, ale znowu możemy pomóc w Javie. Zakładając znormalizowaną liczbę, część "10" kończy się na trzech bitach (jeden mniej niż jedenastu = 1011). Pozostawia to 60 bitów mantysy dla rozszerzonej precyzji (80 bitów) i 48 bitów dla podwójnej precyzji (64 bity).
Jaka jest największa liczba do 11 w każdej precyzji? Znowu użyjmy Java:
import java.math.*;
public class Test
{
public static void main(String[] args)
{
BigDecimal half = new BigDecimal("0.5");
BigDecimal eleven = new BigDecimal(11);
System.out.println(eleven.subtract(half.pow(60)));
System.out.println(eleven.subtract(half.pow(48)));
}
}
Wyniki:
10.999999999999999999132638262011596452794037759304046630859375
10.999999999999996447286321199499070644378662109375
Tak, trzy numery mamy są:
Correct value: 10.999999999999999444888487687421760603063...
11-2^(-60): 10.999999999999999999132638262011596452794037759304046630859375
11-2^(-48): 10.999999999999996447286321199499070644378662109375
Teraz wyszło najbliższą wartość do prawidłowego dla każdej precyzji - dla większej precyzji jest mniej niż 11. Zaokrąglij każdą z tych wartości do wartości długiej, a otrzymasz odpowiednio 10 i 11.
Mam nadzieję, że jest wystarczająco dużo dowodów, aby przekonać niedowiarków;)
są takie same (obie 11) w moim systemie? –
z czym to zestawiasz? – Joseph
Dla zabawy wypróbuj zmienną lokalną i zobacz, czy to coś zmienia. –