nawet jeśli kompilator używa większą precyzję niż wewnętrzne podwójne dla obliczania xi * xd, powinien to robić konsekwentnie
czy wymagana czy nie (omówione poniżej), to z pewnością nie stało się: Stackoverflow jest zaśmiecony pytaniami od ludzi, którzy widzieli podobne pozorne obliczenia, zmieniając się bez żadnego rzekomego powodu w ramach tego samego programu.
C++ standardowy projekt n3690 mówi (Kopalnia nacisk):
Wartości pływających argumentów i wyników pływających wyrażeń może być reprezentowane w większej precyzji i zakresie niż wymagany przez rodzaj; typy nie zostały w ten sposób zmienione.62
62) Operatorzy odlewu i przydziałów muszą nadal wykonywać określone konwersje zgodnie z opisem w punktach 5.4, 5.2.9 i 5.17.
Tak - w porozumieniu z komentarzem i wbrew moim wcześniejszym edycji MM - to wersja z (double)
obsadzie że musi zaokrągla się do 64-bitowej double
- który ewidentnie dzieje się> = 1180000000 w biegu udokumentowanym w pytaniu - przed obcięciem do liczby całkowitej. Bardziej ogólna liczba sans 62) pozostawia kompilatorowi wolność, aby nie zaokrąglać wcześniej w drugim przypadku.
[c.limits]/3 mówi, że FLT_EVAL_METHOD powinno zostać zaimportowane z C99. IOW Oczekiwałem, że nie powinno być dozwolone używanie innej precyzji dla xi * xd w jednej linii niż w innej linii.
Sprawdź cppreference page:
Niezależnie od wartości FLT_EVAL_METHOD, każde wyrażenie zmiennoprzecinkowe mogą być zlecane, że jest obliczana tak, jakby wszystkie wyniki pośrednie mają nieskończony zasięg i precyzję (chyba #pragma STDC FP_CONTRACT jest wyłączony)
Jak tmyklebu komentarzach, to nadal:
Odlewanie i przydział usuwają wszelki dodatkowy zakres i precyzję: modeluje to działanie polegające na zapisaniu wartości z precyzyjnie rozszerzonego rejestru FPU do pamięci o standardowej wielkości.
Ten ostatni zgadza się z częścią "62)" standardu.
M.M. komentarzy:
STDC FP_CONTRACT nie wydaje się pojawiać w C++ standard, a także to nie jest dla mnie jasne, dokładnie, w jakim stopniu zachowanie C99 jest „importowanej”
Nie pojawia się w projekcie Spojrzałem na. Sugeruje to, że C++ nie gwarantuje jej dostępności, pozostawiając domyślną wzmiankę powyżej o "dowolne wyrażenie zmiennoprzecinkowe może być zakontraktowane", ale wiemy na M.M. komentarze i cytaty Standard i cppreference nad rzutem (double)
jest wyjątkiem wymuszającym zaokrąglanie do 64 bitów.
C++ standardowy projekt wspomniano powyżej mówi <cfloat>
:
Treści są takie same jak w nagłówku biblioteka standardowa C. Patrz również: ISO C 7.1.5, 5.2.4.2.2, 5.2.4.2.1.
Jeśli jeden z tych C wymaganych standardów STDC FP_CONTRACT
istnieje większa szansa, że był przenośny do użytku programów C++, ale nie wcześniej badanych implementacje dla wsparcia.
Zauważ, że musisz oboje opracować 'xi * xd' jako' long double' i wykonać konwersję na liczbę całkowitą z 'long double', aby uzyskać to błędnie; 1e9 * 1,18 kończy się o około 1/4 ulp od 1,18e9. – tmyklebu
Powiązane: https://gc.gnu.org/bugzilla/show_bug.cgi?id=323#c127 – Nemo