Portál AbcLinuxu, 21. července 2025 00:38


Dotaz: Porovnání doublů

5.8.2016 18:06 Jirka
Porovnání doublů
Přečteno: 1975×
Odpovědět | Admin
Potřebuji porovnat, zda číslo leží v nějakém intervalu. Znám spodní a horní hranici, a jestli je to uzavřený nebo otevřený interval. Problém je, že double je nepřesný. Řekněme, že horní hranice není přesně reprezentovatelná jako double, takže třeba mám li otevřený interval (0;8,1), tak bych chtěl porovnávat horní hranici na nevyšší menší číslo než 8,1 jako na uzavřený (řekněme a <= 8.009). Naopak, pokud je uzavřený (0;8,1>, tak bych chtěl porovnávat jako otevřený na nejnižší vyšší (např a < 8.1000001). Čísla jsou jen příklad a teď netuším, jestli zrovna jsou reprezentovatelná přesně. Čísla intervalu znám během kompilace. Otázka zní, zda mohu nějak kompilátoru říct "sem mi dosaď nejnižší vyšší číslo" a "sem mi dosaď nejvyšší nižší číslo", nebo jak toho docílit jinak?

Řešení dotazu:


Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

5.8.2016 18:16 Kit | skóre: 45 | Brno
Rozbalit Rozbalit vše Re: Porovnání doublů
Odpovědět | | Sbalit | Link | Blokovat | Admin
Klidně použij operátory < a <=. Dělají přesně to, co potřebuješ.
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
7.8.2016 11:45 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Porovnání doublů
To těžko. Tazatel potřebuje zadané číslo zaokrouhlit jednou nahoru a jednou dolů, podle toho, zda má otevřený nebo uzavřený interval. K tomu zaokrouhlování dochází při překladu při parsování dané konstanty, nemůže na to mít vliv, s jakým operátorem se ta konstanta použije.
14.8.2016 00:30 Atom321 | skóre: 20
Rozbalit Rozbalit vše Re: Porovnání doublů
Stejným způsobem je zaokrouhlená i to "číslo", které se porovnává s tou konstantou. Operátory porovnání tedy budou fungovat správně. Příklad kódu:
    double a;
    a =     4.000000000000000000;
    a = a - 0.000000000000000001;

    if (a == 3.99999999999999999999) {
        printf("a %.20f == %.20f\n", a, 3.99999999999999999999);
    }
Vypíše:
a 4.00000000000000000000 == 4.00000000000000000000
Tedy, v obou případech se číslo 3.99999999999999999999, které není reprezentovatelné jako double, zaokrouhlí na 4 a porovnání bude fungovat.
14.8.2016 09:23 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Porovnání doublů
To ale předpokládáte jiný způsob porovnávání, než který chtěl použít tazatel. Tazatel chtěl zaokrouhlovat nahoru nebo dolů podle toho, zda má otevřený nebo uzavřený interval - takže "v obou případech stejně" je přesně to, co tazatel nechtěl.
15.8.2016 01:02 Atom321 | skóre: 20
Rozbalit Rozbalit vše Re: Porovnání doublů
Jak nechtěl "v obou případech stejně"? Cituji:
Řekněme, že horní hranice není přesně reprezentovatelná jako double, takže třeba mám li otevřený interval (0;8,1), tak bych chtěl porovnávat horní hranici na nejvyšší menší číslo než 8,1 jako na uzavřený (řekněme a <= 8.009). Naopak, pokud je uzavřený (0;8,1>, tak bych chtěl porovnávat jako otevřený na nejnižší vyšší (např a < 8.1000001).
Pro vysvětlení vyjdu z tazatelova předpokladu, že číslo 8,1 není v double reprezentovatelné, nejbližší reprezentovatelná jsou 8.009 (nižší) a 8.1000001 (vyšší).

Pokud toto platí, pak mezi 8.009 a 8.1000001 není v double žádné jiné číslo. Jinak řečeno, 8.009 je nejvyšší double číslo menší než 8.1000001. V tom případě pro každé x<8.1000001 platí, že x <= 8.009. Z toho vyplývá, že ty dva tazatelem navržené způsoby porovnání jsou ekvivalentní. Tedy jinak řečeno, porovnání dopadne v obou případech stejně.
15.8.2016 07:00 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Porovnání doublů
Ano, pro tenhle jednoduchý případ je vaše řešení ekvivalentní. Ale když uvádíte jiný postup řešení, než popisoval tazatel, je vhodné na to explicitně upozornit - například proto, že vaše řešení má jiné předpoklady, a tazatel by si měl ověřit, že v jeho skutečném problému jsou ty předpoklady splněné.
15.8.2016 13:58 Atom321 | skóre: 20
Rozbalit Rozbalit vše Re: Porovnání doublů
Ano, pro tenhle jednoduchý případ je vaše řešení ekvivalentní.
Není. Ekvivalentní jsou porovnání na otevřený a uzavřený interval, které si navrhnul sám tazatel. Tohle druhé řešení je jiné. Které z nich je správně, to nevím - protože není úplně jasné, čeho vlastně tazatel potřebuje docílit. Zjevně to, co "potřebuje" a co "chce" jsou dvě odlišné věci.
Ale když uvádíte jiný postup řešení, než popisoval tazatel, je vhodné na to explicitně upozornit - například proto, že vaše řešení má jiné předpoklady, a tazatel by si měl ověřit, že v jeho skutečném problému jsou ty předpoklady splněné.
Tohle řešení ale není moje, navrhl ho Váš předřečník, pan Kit. Já jsem jen doplnil další informace k Vaší reakci na něj. Rozpory v předpokladech jsem zjistil až posléze, když jsem se k diskusi vrátil další den (tedy spíše noc).

Jinak: radím, jak nejlíp umím, tak mě za to prosím nepeskujte. Pokud se vám zdá, že pánovi radím špatně, tak mu prostě poraďte lépe.
6.8.2016 11:50 qqq
Rozbalit Rozbalit vše Re: Porovnání doublů
Odpovědět | | Sbalit | Link | Blokovat | Admin
Cisla s plovouci carkou maji v kazdem jazyku preddefinovany konstanty udavajici jejich presnost. Napriklad Fortran ma funkci epsilon(), v C je makro DBL_EPSILON (z float.h) a v C++ uz i funkce isless() (z cmath). Interprety uz maji dokonce tyto veci osetrene (Python).
Jendа avatar 8.8.2016 20:31 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Porovnání doublů
Já mám ve svém float.h komentář
/* The difference between 1 and the least value greater than 1 that is representable in the given floating point type, b**1-p. */
což podle mě není to, co tazatel chce -- protože pro číslo 10000 bude epsilon jiné.
Jendа avatar 8.8.2016 20:35 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Porovnání doublů
Šlo by to nejspíš oprasit roztržením přes frexp a následným porovnáním na tom. Jen pozor na overflow…
9.8.2016 01:09 Sten
Rozbalit Rozbalit vše Re: Porovnání doublů
To není tak jednoduché. Epsilon lze použít pro porovnání dvou konstant, navíc je potřeba ho škálovat s velikostí čísel: fabs(číslo1 - číslo2) <= DBL_EPSILON * fmax(fabs(číslo1), fabs(číslo2))

Ale pokud se s těmi čísly operuje více, tak možná deviace začne s každou operací narůstat. Třeba 0.1 + 0.2 má menší deviaci (a dá jiný výsledek) než 0.1 + 0.2 + 0.1 + 0.2 - 0.3, a přitom jsou to téměř totožná čísla (matematicky by oboje mělo být 0.3).

Python nic ošetřené nemá:
>>> .1 + .2 == .3
False
Bystroushaak avatar 15.8.2016 01:58 Bystroushaak | skóre: 36 | blog: Bystroushaakův blog | Praha
Rozbalit Rozbalit vše Re: Porovnání doublů
Python nic ošetřené nemá:
3.5, nebo 3.6 to tuším nějak řeší. Ale zachytil jsem jen titulky, nečetl jsem podrobnosti.
Bystroushaak avatar 15.8.2016 10:36 Bystroushaak | skóre: 36 | blog: Bystroushaakův blog | Praha
Rozbalit Rozbalit vše Re: Porovnání doublů
The string representation of a float now uses the shortest decimal number that has the same underlying value — for example, repr(1.1) was '1.1000000000000001' in Python 2.6, but is just '1.1' in Python 2.7 and 3.1+, because both are represented the same way in a 64-bit float.
a
math.isclose (and the corresponding complex version, cmath.isclose) determines whether two values are “close enough”. Intended to do the right thing when comparing floats.
a
decimal.Decimal, fractions.Fraction, and floats now interoperate a little more nicely: numbers of different types hash to the same value; all three types can be compared with one another; and most notably, the Decimal and Fraction constructors can accept floats directly.
-- https://eev.ee/blog/2016/07/31/python-faq-why-should-i-use-python-3/

Takže to taky neřeší automaticky ve výpočtech (pokud člověk nepoužije fraction místo double).
7.8.2016 11:48 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Porovnání doublů
Odpovědět | | Sbalit | Link | Blokovat | Admin
Standard IEEE 754 definuje 5 různých způsobů zaokrouhlování. Vy potřebujete přepínat mezi zaokrouhlováním k nule nebo zaokrouhlováním k plus nebo mínus nekonečnu (pokud mohou být čísla i záporná). Přepínání režimů v GNU C je popsané zde: Rounding Modes.
12.8.2016 17:05 zlobr
Rozbalit Rozbalit vše Re: Porovnání doublů
Odpovědět | | Sbalit | Link | Blokovat | Admin
Rozšiřování fotbalové brány, aby hráči netrefovali tyče :-D

Tohle je k ničemu. Co s nepřesností toho 'a' na levé straně? Pokud potřebuješ přesné výpočty a porovnávání, tak nepoužívej double.
12.8.2016 21:50 ZAH | skóre: 43 | blog: ZAH
Rozbalit Rozbalit vše Re: Porovnání doublů
Odpovědět | | Sbalit | Link | Blokovat | Admin
Java

Long l = Double.doubleToLongBits(new Double(1225548.1254))+1l;

Double d = Double.longBitsToDouble(l);
13.8.2016 20:29 karl82 | skóre: 6
Rozbalit Rozbalit vše Re: Porovnání doublů
proc new Double(1225548.1254)?
Jendа avatar 13.8.2016 21:22 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Porovnání doublů
Ukázková hodnota.

A jinak hezký trik, to by mě nenapadlo.
14.8.2016 03:34 karl82 | skóre: 6
Rozbalit Rozbalit vše Re: Porovnání doublů
nejde o hodnotu. jde o new Double(<foobar>). Novou instanci Double

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.