Co jest złego w używaniu == do porównywania liczb zmiennoprzecinkowych w Javie?

177

Zgodnie z tą stroną java.sun == jest operatorem porównania równości dla liczb zmiennoprzecinkowych w Javie.

Jednak gdy wpisuję ten kod:

if(sectionID == currentSectionID)

do mojego edytora i uruchamiam analizę statyczną, otrzymuję: „JAVA0078 Wartości zmiennoprzecinkowe w porównaniu z ==”

Co jest złego w używaniu ==do porównywania wartości zmiennoprzecinkowych? Jaki jest właściwy sposób, aby to zrobić? 

user128807
źródło
29
Ponieważ porównywanie elementów zmiennoprzecinkowych z == jest problematyczne, używanie ich jako identyfikatorów jest nierozsądne; nazwy w przykładowym kodzie sugerują, że właśnie to robisz; preferowane są długie liczby całkowite (długie) i de facto standard identyfikatorów.
Carl Manaster,
4
Tak, czy to tylko przypadkowy przykład, czy faktycznie używasz liczb zmiennoprzecinkowych jako identyfikatorów? Czy jest powód?
Według Wiklandera,
5
"dla pól typu float użyj metody Float.compare, a dla pól podwójnych Double.compare. Specjalne traktowanie pól typu float i double jest konieczne ze względu na istnienie Float.NaN, -0.0f i analogicznych podwójnych stałych; szczegóły w dokumentacji Float.equals. " (Joshua Bloch: Effective Java)
lbalazscs

Odpowiedzi:

211

prawidłowy sposób testowania elementów zmiennoprzecinkowych pod kątem „równości” to:

if(Math.abs(sectionID - currentSectionID) < epsilon)

gdzie epsilon to bardzo mała liczba, np. 0,00000001, w zależności od pożądanej precyzji.

Zwycięzca
źródło
26
Zobacz link w zaakceptowanej odpowiedzi ( cygnus-software.com/papers/comparingfloats/comparingfloats.htm ), aby dowiedzieć się, dlaczego ustalony epsilon nie zawsze jest dobrym pomysłem. W szczególności, gdy wartości w porównywanych zmiennoprzecinkowych stają się duże (lub małe), epsilon nie jest już odpowiedni. (Używanie epsilon jest w porządku, jeśli wiesz, że wszystkie wartości zmiennoprzecinkowe są stosunkowo rozsądne.)
PT,
1
@PT Czy może pomnożyć epsilon przez jedną liczbę i zmienić funkcję na, if(Math.abs(sectionID - currentSectionID) < epsilon*sectionIDaby rozwiązać ten problem?
entuzjastyczny
3
To może być nawet najlepsza jak dotąd odpowiedź, ale nadal zawiera błędy. Skąd bierzesz epsilon?
Michael Piefel
1
@MichaelPiefel jest już napisane: „w zależności od pożądanej precyzji”. Pływaki ze swej natury są czymś w rodzaju wartości fizycznych: interesuje Cię tylko ograniczona liczba pozycji w zależności od całkowitej niedokładności, a wszelkie różnice poza nią są uważane za dyskusyjne.
ivan_pozdeev
Ale OP tak naprawdę chciał tylko przetestować pod kątem równości, a ponieważ wiadomo, że jest to niewiarygodne, musi użyć innej metody. Mimo to nie pojmuję, że wie, jaka jest jego „pożądana precyzja”; więc jeśli wszystko, czego chcesz, to bardziej wiarygodny test równości, pozostaje pytanie: skąd bierzesz epsilon? Zaproponowałem użycie Math.ulp()w mojej odpowiedzi na to pytanie.
Michael Piefel
53

Wartości zmiennoprzecinkowe mogą się nieco różnić, więc mogą nie być tak dokładnie równe. Na przykład, ustawiając wartość zmiennoprzecinkową na „6,1”, a następnie drukując ją ponownie, można otrzymać raportowaną wartość w rodzaju „6.099999904632568359375”. Jest to fundamentalne dla sposobu działania pływaków; dlatego nie chcesz ich porównywać za pomocą równości, ale raczej porównania w zakresie, to znaczy, jeśli różnica liczby zmiennoprzecinkowej do liczby, z którą chcesz ją porównać, jest mniejsza niż pewna wartość bezwzględna.

Ten artykuł w rejestrze daje dobry przegląd powodów takiego stanu rzeczy; przydatna i ciekawa lektura.

Paul Sonier
źródło
@kevindtimm: więc przeprowadzisz testy równości w ten sposób, jeśli (numer == 6.099999904632568359375) za każdym razem, gdy chcesz znać liczbę, wynosi 6,1 ... Tak, masz rację ... wszystko w komputerze jest ściśle deterministyczne, tylko tyle, że przybliżenia używane dla liczb zmiennoprzecinkowych są sprzeczne z intuicją podczas wykonywania zadań matematycznych.
Newtopian
Wartości zmiennoprzecinkowe są niedeterministycznie nieprecyzyjne tylko na bardzo specyficznym sprzęcie .
Stuart P. Bentley
1
@Stuart Mogę się mylić, ale nie sądzę, aby błąd FDIV był niedeterministyczny. Odpowiedzi udzielone przez sprzęt nie były zgodne ze specyfikacją, ale były deterministyczne, ponieważ te same obliczenia zawsze dawały ten sam nieprawidłowy wynik
Gravity.
@Gravity Możesz argumentować, że każde zachowanie jest deterministyczne, biorąc pod uwagę określony zestaw zastrzeżeń.
Stuart P. Bentley
Wartości zmiennoprzecinkowe nie są nieprecyzyjne. Każda wartość zmiennoprzecinkowa jest dokładnie tym, czym jest. Nieprecyzyjne mogą być wyniki obliczeń zmiennoprzecinkowych . Ale strzeż się! Kiedy widzisz w programie coś takiego jak 0.1, nie jest to wartość zmiennoprzecinkowa. To literał zmiennoprzecinkowy - ciąg znaków, który kompilator konwertuje na wartość zmiennoprzecinkową wykonując obliczenia .
Solomon Slow
22

Tylko po to, aby podać powód tego, co mówią wszyscy inni.

Binarna reprezentacja pływaka jest trochę denerwująca.

W systemie binarnym większość programistów zna korelację między 1b = 1d, 10b = 2d, 100b = 4d, 1000b = 8d

Cóż, działa też w drugą stronę.

.1b = .5d, .01b = .25d, .001b = .125, ...

Problem polega na tym, że nie ma dokładnego sposobu przedstawienia większości liczb dziesiętnych, takich jak .1, .2, .3 itd. Wszystko, co możesz zrobić, to przybliżenie w systemie dwójkowym. System trochę zaokrągla, gdy drukowane są liczby, tak że wyświetla .1 zamiast .10000000000001 lub .999999999999 (które są prawdopodobnie tak samo zbliżone do zapisanej reprezentacji jak .1)

Edytuj z komentarza: Powodem, dla którego jest to problem, są nasze oczekiwania. W pełni spodziewamy się, że 2/3 zostanie sfałszowane w pewnym momencie, gdy zamienimy je na dziesiętne, albo .7, .67 lub .666667 .. Ale nie oczekujemy, że .1 zostanie automatycznie zaokrąglone w taki sam sposób, jak 2/3 - i to jest dokładnie to, co się dzieje.

Nawiasem mówiąc, jeśli jesteś ciekawy, liczba, którą przechowuje wewnętrznie, jest czystą reprezentacją binarną przy użyciu binarnej „notacji naukowej”. Więc jeśli powiesz mu, aby zapisał liczbę dziesiętną 10,75d, zapisze 1010b dla 10 i .11b dla dziesiętnej. Więc zapisze .101011, a następnie zapisuje kilka bitów na końcu, aby powiedzieć: Przenieś przecinek dziesiętny o cztery miejsca w prawo.

(Chociaż technicznie nie jest to już przecinek dziesiętny, jest to teraz punkt binarny, ale ta terminologia nie uczyniłaby rzeczy bardziej zrozumiałymi dla większości ludzi, którzy uznaliby tę odpowiedź za użyteczną).

Bill K.
źródło
1
@Matt K - um, nie stały punkt; jeśli „zapiszesz kilka bitów na końcu, aby powiedzieć, że przesuń kropkę dziesiętną [N] bitów w prawo”, to jest zmiennoprzecinkowe. Punkt stały przyjmuje położenie punktu radix jako, cóż, ustalonego. Ponadto, ogólnie rzecz biorąc, ponieważ przesunięcie punktu binamalnego (?) Zawsze może zostać wykonane w taki sposób, aby pozostawić `` 1 '' na skrajnej lewej pozycji, znajdziesz kilka systemów, które pomijają wiodącą `` 1 '', poświęcając uwolnioną w ten sposób przestrzeń (1 bit!), aby zwiększyć zakres wykładnika.
JustJeff,
Problem nie ma nic wspólnego z reprezentacją binarną i dziesiętną. W przypadku dziesiętnych liczb zmiennoprzecinkowych nadal masz takie rzeczy, jak (1/3) * 3 == 0.9999999999999999999999999999.
dan04
2
@ dan04 tak, ponieważ 1/3 nie ma reprezentacji dziesiętnej LUB binarnej, ma reprezentację trójargumentową i zostałaby poprawnie przekonwertowana w ten sposób :). Wszystkie wymienione przeze mnie liczby (0,1, 0,25 itd.) Mają doskonałe odwzorowania dziesiętne, ale nie mają reprezentacji binarnej - a ludzie są przyzwyczajeni do tych, które mają „dokładne” reprezentacje. BCD poradziłby sobie z nimi doskonale. To jest różnica.
Bill K
1
Powinno to mieć znacznie więcej głosów pozytywnych, ponieważ opisuje PRAWDZIWY problem związany z problemem.
Levite,
19

Co jest złego w używaniu == do porównywania wartości zmiennoprzecinkowych?

Ponieważ to nieprawda 0.1 + 0.2 == 0.3

AakashM
źródło
7
o czym Float.compare(0.1f+0.2f, 0.3f) == 0?
Aquarius Power
0,1f + 0,2f == 0,3f ale 0,1d + 0,2d! = 0,3d. Domyślnie 0,1 + 0,2 to podwojenie. 0,3 to również podwójna.
burnabyRails
12

Myślę, że wokół floatów (i dubletów) jest sporo zamieszania, dobrze jest to wyjaśnić.

  1. Nie ma nic złego w używaniu liczb zmiennoprzecinkowych jako identyfikatorów w zgodnej ze standardami JVM [*]. Jeśli po prostu ustawisz identyfikator float na x, nic z nim nie rób (tj. Żadnych arytmetyki), a później przetestujesz y == x, wszystko będzie dobrze. Nie ma też nic złego w używaniu ich jako kluczy w HashMap. To, czego nie możesz zrobić, to zakładać równości, takie jak x == (x - y) + yitp. To powiedziawszy, ludzie zwykle używają typów całkowitych jako identyfikatorów i możesz zauważyć, że większość ludzi tutaj jest zniechęcona tym kodem, więc ze względów praktycznych lepiej jest przestrzegać konwencji . Zauważ, że jest tyle różnych doublewartości, ile jest długości values, więc nic nie zyskujesz używając double. Ponadto generowanie „następnego dostępnego identyfikatora” może być trudne w przypadku podwójnych i wymaga pewnej znajomości arytmetyki zmiennoprzecinkowej. Nie warto.

  2. Z drugiej strony opieranie się na liczbowej równości wyników dwóch matematycznie równoważnych obliczeń jest ryzykowne. Dzieje się tak z powodu błędów zaokrąglania i utraty precyzji podczas konwersji z reprezentacji dziesiętnej na dwójkową. Zostało to omówione na śmierć w SO.

[*] Kiedy powiedziałem „JVM zgodny ze standardami”, chciałem wykluczyć niektóre implementacje JVM z uszkodzeniem mózgu. Zobacz to .

quant_dev
źródło
Używając liczb zmiennoprzecinkowych jako identyfikatorów, należy uważać, aby albo upewnić się, że są one porównywane przy użyciu ==zamiast equals, albo też upewnić się, że żadna liczba zmiennoprzecinkowa, która porównuje ze sobą nierówne, nie zostanie zapisana w tabeli. W przeciwnym razie program, który próbuje np. Policzyć, ile unikatowych wyników może zostać wygenerowanych z wyrażenia po podaniu różnych danych wejściowych, może uznać każdą wartość NaN za unikalną.
supercat
Powyższe odnosi się do Float, a nie do float.
quant_dev
O czym mówisz Float? Jeśli ktoś spróbuje zbudować tabelę unikalnych floatwartości i porównać je z ==okropnymi regułami porównania IEEE-754, spowoduje to zalanie tabeli NaNwartościami.
supercat
floattyp nie ma equalsmetody.
quant_dev
Ach - nie miałem na myśli equalsmetody instancji, ale raczej metodę statyczną (chyba w Floatklasie), która porównuje dwie wartości typu float.
supercat
9

Jest to problem, który nie dotyczy języka java. Użycie == do porównania dwóch liczb zmiennoprzecinkowych / podwójnych / dowolnej liczby dziesiętnej może potencjalnie spowodować problemy ze względu na sposób ich przechowywania. Liczba zmiennoprzecinkowa pojedynczej precyzji (zgodnie ze standardem IEEE 754) ma 32 bity, rozmieszczone w następujący sposób:

1 bit - Znak (0 = dodatni, 1 = ujemny)
8 bitów - Wykładnik (specjalna (bias-127) reprezentacja xw 2 ^ x)
23 bity - Mantisa. Rzeczywisty numer, który jest przechowywany.

To właśnie modliszka powoduje problem. To trochę jak notacja naukowa, tylko liczba o podstawie 2 (binarnej) wygląda na 1,110011 x 2 ^ 5 lub coś podobnego. Ale w systemie binarnym pierwsza 1 to zawsze 1 (z wyjątkiem reprezentacji 0)

Dlatego, aby zaoszczędzić trochę miejsca w pamięci (gra słów zamierzona), IEEE zdecydowało, że należy założyć 1. Na przykład modliszka 1011 to tak naprawdę 1,1011.

Może to powodować pewne problemy z porównaniem, szczególnie w przypadku 0, ponieważ 0 nie może być dokładnie reprezentowane w zmiennej zmiennoprzecinkowej. Jest to główny powód, dla którego odradza się stosowanie ==, oprócz problemów z matematyką zmiennoprzecinkową opisanych w innych odpowiedziach.

Java ma wyjątkowy problem polegający na tym, że język jest uniwersalny na wielu różnych platformach, z których każda może mieć swój własny, unikalny format zmiennoprzecinkowy. Dlatego jeszcze ważniejsze jest unikanie ==.

Prawidłowy sposób porównywania dwóch zmiennych (umysł niezwiązanych z językiem) pod kątem równości jest następujący:

if(ABS(float1 - float2) < ACCEPTABLE_ERROR)
    //they are approximately equal

gdzie ACCEPTABLE_ERROR jest #defined lub inną stałą równą 0,000000001 lub inną wymaganą precyzją, jak wspomniał już Victor.

Niektóre języki mają wbudowaną tę funkcję lub tę stałą, ale generalnie jest to dobry zwyczaj.

CodeFusionMobile
źródło
3
Java ma zdefiniowane zachowanie dla pływaków. To nie jest zależne od platformy.
Yishai
9

Na dzień dzisiejszy szybki i łatwy sposób to:

if (Float.compare(sectionID, currentSectionID) == 0) {...}

Jednak dokumenty nie określają jasno wartości różnicy marginesów ( epsilon z odpowiedzi @Victor), która jest zawsze obecna w obliczeniach na liczbach zmiennoprzecinkowych, ale powinna być rozsądna, ponieważ jest częścią standardowej biblioteki językowej.

Jeśli jednak potrzebna jest wyższa lub dostosowana do potrzeb precyzja, to

float epsilon = Float.MIN_NORMAL;  
if(Math.abs(sectionID - currentSectionID) < epsilon){...}

to kolejna opcja rozwiązania.

alisa
źródło
1
Dokumenty, które połączyłeś, stwierdzają, że „wartość 0, jeśli f1 jest liczbowo równa f2”, co oznacza, że ​​jest to to samo, co robienie tego, (sectionId == currentSectionId)co nie jest dokładne dla punktów zmiennoprzecinkowych. metoda epsilon jest lepszym podejściem, co jest w tej odpowiedzi: stackoverflow.com/a/1088271/4212710
typoerrpr
8

Wartości punktów spłaty nie są wiarygodne z powodu błędu zaokrąglenia.

W związku z tym prawdopodobnie nie powinny być używane jako wartości klucza, takie jak identyfikator sekcji. Zamiast tego użyj liczb całkowitych lub longjeśli intnie zawiera wystarczającej liczby możliwych wartości.

Eric Wilson
źródło
2
Zgoda. Biorąc pod uwagę, że są to identyfikatory, nie ma powodu, aby komplikować sprawy arytmetyką zmiennoprzecinkową.
Yohnny,
2
Albo długo. W zależności od tego, ile unikalnych identyfikatorów zostanie wygenerowanych w przyszłości, int może nie być wystarczająco duży.
Wayne Hartman
Jak dokładna jest podwójna w porównaniu do float?
Arvindh Mani
1
@ArvindhMani doublesą znacznie dokładniejsze, ale są to również wartości zmiennoprzecinkowe, więc moja odpowiedź miała zawierać zarówno floati double.
Eric Wilson
7

Oprócz wcześniejszych odpowiedzi powinieneś mieć świadomość, że istnieją dziwne zachowania związane z -0.0fi +0.0f(są, ==ale nie equals) i Float.NaN(jest, equalsale nie ==) (mam nadzieję, że mam rację - argh, nie rób tego!).

Edycja: Sprawdźmy!

import static java.lang.Float.NaN;
public class Fl {
    public static void main(String[] args) {
        System.err.println(          -0.0f   ==              0.0f);   // true
        System.err.println(new Float(-0.0f).equals(new Float(0.0f))); // false
        System.err.println(            NaN   ==               NaN);   // false
        System.err.println(new Float(  NaN).equals(new Float( NaN))); // true
    }
} 

Witamy w IEEE / 754.

Tom Hawtin - haczyk
źródło
Jeśli coś jest ==, to są identyczne co do bitu. Jak mogliby nie być równi ()? Może masz to do tyłu?
mkb
@Matt NaN jest wyjątkowy. Double.isNaN (double x) w Javie jest faktycznie zaimplementowany jako {return x! = X; } ...
quant_dev
1
Z ==liczb zmiennoprzecinkowych nie oznacza, że ​​liczby są „identyczne z bitem” (ta sama liczba może być reprezentowana za pomocą różnych wzorów bitowych, chociaż tylko jeden z nich ma postać znormalizowaną). Jak dobrze, -0.0fi 0.0fsą reprezentowane przez różne wzorce bitowe (bit znaku jest inny), ale porównują jako równe z ==(ale nie zequals ). Twoje założenie, że ==jest to porównanie bitowe, jest ogólnie rzecz biorąc błędne.
Pavel Minaev
5

Możesz użyć Float.floatToIntBits ().

Float.floatToIntBits(sectionID) == Float.floatToIntBits(currentSectionID)
aamadmi
źródło
1
Jesteś na dobrej drodze. floatToIntBits () jest właściwą drogą, ale byłoby łatwiej po prostu użyć wbudowanej funkcji equals () Floata. Zobacz tutaj: stackoverflow.com/a/3668105/2066079 . Możesz zobaczyć, że domyślna funkcja equals () wykorzystuje wewnętrznie floatToIntBits.
dberm22
1
Tak, jeśli są to obiekty typu Float. Możesz użyć powyższego równania dla prymitywów.
aamadmi
4

Po pierwsze, czy pływają czy pływają? Jeśli jednym z nich jest Float, należy użyć metody equals (). Ponadto prawdopodobnie najlepiej jest użyć statycznej metody Float.compare.

omerkudat
źródło
4

Następujące automatycznie używa najlepszej precyzji:

/**
 * Compare to floats for (almost) equality. Will check whether they are
 * at most 5 ULP apart.
 */
public static boolean isFloatingEqual(float v1, float v2) {
    if (v1 == v2)
        return true;
    float absoluteDifference = Math.abs(v1 - v2);
    float maxUlp = Math.max(Math.ulp(v1), Math.ulp(v2));
    return absoluteDifference < 5 * maxUlp;
}

Oczywiście możesz wybrać więcej lub mniej niż 5 ULP („jednostka na ostatnim miejscu”).

Jeśli jesteś w bibliotece Apache Commons, Precisionklasa ma compareTo()i equals()z epsilon i ULP.

Michael Piefel
źródło
przy zmianie zmiennej float na double ta metoda nie działa tak, jak jest DoubleEqual (0,1 + 0,2-0,3, 0,0) == false
hychou
Wygląda na to, że potrzebujesz więcej niż 10_000_000_000_000_000L jako czynnika, aby doubleto pokryć.
Michael Piefel
3

możesz chcieć, żeby to było ==, ale 123.4444444444443! = 123.4444444444442

KM.
źródło
2

Dwa różne obliczenia, które dają równe liczby rzeczywiste, niekoniecznie dają równe liczby zmiennoprzecinkowe. Osoby, które używają == do porównywania wyników obliczeń, zwykle są tym zaskoczone, więc ostrzeżenie pomaga oznaczyć to, co w przeciwnym razie mogłoby być subtelnym i trudnym do odtworzenia błędem.

VoiceOfUnreason
źródło
2

Czy masz do czynienia z zewnętrznym kodem, który używałby liczb zmiennoprzecinkowych do rzeczy o nazwach sectionID i currentSectionID? Po prostu ciekawy.

@Bill K: „Binarna reprezentacja liczby zmiennoprzecinkowej jest trochę denerwująca”. Jak to? Jak byś to zrobił lepiej? Istnieją pewne liczby, których nie można właściwie przedstawić w żadnej bazie, ponieważ nigdy się nie kończą. Pi jest dobrym przykładem. Możesz to tylko przybliżyć. Jeśli masz lepsze rozwiązanie, skontaktuj się z firmą Intel.

xcramps
źródło
1

Jak wspomniano w innych odpowiedziach, gry podwójne mogą mieć niewielkie odchylenia. Mógłbyś napisać własną metodę porównywania ich przy użyciu „dopuszczalnego” odchylenia. Jednak ...

Istnieje klasa Apache do porównywania gier podwójnych: org.apache.commons.math3.util.Precision

Zawiera kilka interesujących stałych: SAFE_MINiEPSILON , które są maksymalnymi możliwymi odchyleniami prostych operacji arytmetycznych.

Zapewnia również niezbędne metody porównywania, równych lub okrągłych gier podwójnych. (przy użyciu ulps lub bezwzględnego odchylenia)

bvdb
źródło
1

W jednej linii odpowiedzi mogę powiedzieć, powinieneś użyć:

Float.floatToIntBits(sectionID) == Float.floatToIntBits(currentSectionID)

Aby dowiedzieć się więcej o prawidłowym używaniu operatorów pokrewnych, omówię tutaj kilka przypadków: Ogólnie rzecz biorąc, istnieją trzy sposoby testowania ciągów znaków w Javie. Możesz użyć ==, .equals () lub Objects.equals ().

Czym się różnią? == testuje jakość referencyjną w ciągach znaków, co oznacza sprawdzenie, czy te dwa obiekty są takie same. Z drugiej strony .equals () sprawdza logicznie, czy dwa łańcuchy mają taką samą wartość. Na koniec Objects.equals () sprawdza wszystkie wartości null w dwóch ciągach, a następnie określa, czy wywołać .equals ().

Idealny operator w użyciu

Cóż, było to przedmiotem wielu debat, ponieważ każdy z trzech operatorów ma swój unikalny zestaw mocnych i słabych stron. Na przykład == jest często preferowaną opcją podczas porównywania odwołań do obiektu, ale są przypadki, w których może się wydawać, że porównuje również wartości ciągów.

Jednak to, co dostajesz, jest wartością spadkową, ponieważ Java tworzy iluzję, że porównujesz wartości, ale w rzeczywistości tak nie jest. Rozważ dwa poniższe przypadki:

Przypadek 1:

String a="Test";
String b="Test";
if(a==b) ===> true

Przypadek 2:

String nullString1 = null;
String nullString2 = null;
//evaluates to true
nullString1 == nullString2;
//throws an exception
nullString1.equals(nullString2);

Dlatego lepiej jest użyć każdego operatora podczas testowania określonego atrybutu, dla którego został zaprojektowany. Jednak w prawie wszystkich przypadkach Objects.equals () jest operatorem bardziej uniwersalnym, dlatego też decydują się na to programiści.

Tutaj możesz uzyskać więcej informacji: http://fluentthemes.com/use-compare-strings-java/

Fluent-Themes
źródło
-2

Właściwy sposób byłby

java.lang.Float.compare(float1, float2)
Eric
źródło
7
Float.compare (float1, float2) zwraca wartość typu int, więc nie można jej użyć zamiast float1 == float2 w warunku if. Co więcej, tak naprawdę nie rozwiązuje podstawowego problemu, do którego odnosi się to ostrzeżenie - że jeśli liczby zmiennoprzecinkowe są wynikiem obliczeń numerycznych, może wystąpić float1! = Float2 tylko z powodu błędów zaokrągleń.
quant_dev
1
prawda, nie możesz skopiować wklejania, musisz najpierw sprawdzić dokument.
Eric,
2
To, co możesz zrobić zamiast float1 == float2, to Float.compare (float1, float2) == 0.
odstraszać
29
To nic ci nie kupi - nadal dostajeszFloat.compare(1.1 + 2.2, 3.3) != 0
Pavel Minaev
-2

Jednym ze sposobów zmniejszenia błędu zaokrąglania jest użycie wartości double zamiast float. To nie sprawi, że problem zniknie, ale zmniejszy ilość błędów w programie, a float prawie nigdy nie jest najlepszym wyborem. MOIM ZDANIEM.

Peter Lawrey
źródło