2015-05-27 12 views
8

Jeśli liczba i numer JavaScript w języku JavaScript są takie same (IEEE 754), dlaczego numery z wieloma znaczącymi cyframi są traktowane inaczej?Dlaczego liczby o wielu znaczących cyfrach są obsługiwane inaczej w C# i JavaScript?

var x = (long)1234123412341234123.0; // 1234123412341234176 - C# 
var x =  1234123412341234123.0; // 1234123412341234200 - JavaScript 

I nie chodzi mi o to, że IEEE 754 nie może reprezentować liczbę 1234123412341234123. obawiam się z faktem, że dwie implementacje nie działają takie same numery, które nie mogą być reprezentowane z pełną precyzją.

To może być fakt, IEEE 754 jest pod określony, jedna lub obie implementacje są wadliwe lub które realizują różne warianty IEEE 754.

Ten problem nie jest związany z problemami z zmiennoprzecinkowych formatowania wyjścia w języku C#. Generuję 64-bitowe liczby całkowite. Rozważmy następujący:

long x = 1234123412341234123; Console.WriteLine(x); // Prints 1234123412341234123 double y = 1234123412341234123; x = Convert.ToInt64(y); Console.WriteLine(x); // Prints 1234123412341234176

Te same zmienne drukuje różne ciągi ponieważ wartości są różne.

+0

Dlaczego rzucasz na długo? –

+0

Porównujesz podwójne z floatem, które myślę. Jeśli chcesz mieć możliwość liczenia dużych liczb, sugeruję użycie adresu http://mikemcl.github.io/decimal.js/ i podanie numerów typu ciągu, aby uzyskać pożądaną liczbę cyfr. To nie odpowiada na twoje pytanie, ale może trochę pomóc, jeśli napotkasz problem. Duże liczby są zwykle zapisywane jako wartość formuły, co może powodować błędy zaokrąglania. Dlatego zmienne punkty nie są precyzyjne. Mogłeś wpaść na dużą niedokładność zaokrąglania liczb w javascript. Jeśli chodzi o powód może zajrzeć do https://code.google.com/p/v8/ – Tschallacka

+0

, jest tu jeszcze jeden interesujący problem ... .NET zwykle pokazuje 15 cyfr precyzji, zamiast pełnego 17. – xanatos

Odpowiedz

3

Istnieje wiele problemów tutaj ...

Używasz long zamiast double. trzeba by napisać:

double x = 1234123412341234123.0; 

lub

var x = 1234123412341234123.0; 

Innym problemem jest to, że .NET zaokrągla double s do 15 cyfr przed przekształceniem go do string (tak na przykład przed wydrukowaniem z Console.ToString()).

Na przykład:

string str = x.ToString("f"); // 1234123412341230000.00 

patrz na przykład https://stackoverflow.com/a/1658420/613130

Wewnętrznie liczba wciąż jest z 17 cyfr, tylko to jest pokazane 15.

widać to, jeśli zrobić :

string str2 = x.ToString("r"); // 1.2341234123412342E+18 
2

Numery nie są obsługiwane inaczej, są one wyświetlane tylko w różny sposób.

. NET wyświetla liczbę z 15 cyfr znaczących, natomiast JavaScript wyświetla ją 17 znaczącymi cyframi. Reprezentacja podwójna może zawierać 15-17 znaczących cyfr, w zależności od tego, jaką liczbę zawiera. .NET pokazuje tylko liczbę cyfr, które gwarantowana jest zawsze, ale JavaScript pokazuje wszystkie cyfry, ale może pojawić się ograniczenie precyzji.

.NET zaczyna używać notacji naukowej, gdy wykładnik ma 15, a JavaScript zaczyna jej używać, gdy wykładnik wynosi 21. Oznacza to, że JavaScript wyświetli liczby z 18 do 20 cyfr wypełnionych zerami na końcu.

Konwersja double na long w twoim przykładzie będzie obchodzić sposób podświetlenia .NET podwaja. Liczba zostanie przeliczona bez zaokrąglenia, które ukrywa ograniczenie precyzji, więc w tym przypadku widzisz rzeczywistą wartość, która znajduje się w podwójnym.Powodem, że nie są tylko zera poza 17-tą cyfrą jest to, że wartość jest przechowywana w formie binarnej, a nie dziesiętnej.

1

Uwaga: Ten opiera się standardy wikipedia page

Według strony wikipedia dla standardu określa, że ​​decimal64 powinien mieć 16 cyfr precyzji.

Po to jest decyzja wykonawców co do tego, co należy zrobić z dodatkowymi cyframi.

Można więc powiedzieć, że standard nie został jeszcze doprecyzowany, ale numery te nie zostały zaprojektowane tak, aby pasowały do ​​specyfikacji standardów. Oba języki mają sposoby obsługi większych liczb, więc te opcje mogą być lepiej dopasowane do Ciebie.

+0

16-cyfrowa precyzja jest nakazana wydaje się implikować zarówno. NET i Chrome są uszkodzone, ponieważ numer 9111234123412341 zostaje zmieniony na 9111234123412340 w obu implementacjach. –

+0

@HansMalherbe - Ale oceniasz to na podstawie ich reprezentacji ciągów zamiast rzeczywistej liczby (w języku C# przynajmniej są wyświetlane do [15 sf] (http://stackoverflow.com/a/1658420/1324033)) – Sayse

Powiązane problemy