Wartości zmiennoprzecinkowe podwójnej precyzji w Pythonie? [Zamknięte]

84

Czy istnieją typy danych o większej precyzji niż zmiennoprzecinkowe?

kravemir
źródło
3
W rzeczywistości są to dwa pytania z różnymi odpowiedziami. 1: wartości o podwójnej precyzji w Pythonie to liczby zmiennoprzecinkowe, a 2: typ danych o lepszej dokładności niż liczba zmiennoprzecinkowa byłby dziesiętny. Czy takie pytania można jakoś podzielić? Zaakceptowane adresy odpowiedzi nr 2, ale najczęściej głosowane adresy odpowiedzi nr 1.
bsplosion

Odpowiedzi:

53

Typ danych dziesiętnych

  • W przeciwieństwie do binarnych liczb zmiennoprzecinkowych opartych na sprzęcie, moduł dziesiętny ma precyzję modyfikowalną przez użytkownika (domyślnie 28 miejsc), która może być tak duża, jak potrzeba dla danego problemu.

Jeśli naciskają na Ciebie problemy z wydajnością, spójrz na GMPY

Jakub
źródło
Gdybym zadawał oryginalne pytanie, odpowiedzią byłby @ larsmans (chociaż formalnie nie jest to temat).
Piotr Findeisen
@PiotrFindeisen gdzie jest ta odpowiedź?
Proszę o pomoc,
Nie mam pojęcia, ale teraz odnosiłbym się do @FredFoo. Ogólnie „Wartości zmiennoprzecinkowe podwójnej precyzji w Pythonie?” → „ float-s podwójnej precyzji”
Piotr Findeisen
120

floatTyp wbudowany w Pythonie ma podwójną precyzję (to C doublew CPythonie, Java doublew Jythonie). Jeśli potrzebujesz większej precyzji, zdobądź NumPy i użyj jego numpy.float128.

Fred Foo
źródło
15
Najwyraźniej numpy.float128często ma 64-bitową precyzję w systemie 64-bitowym. numpy.float128(1) + numpy.float128(2**-64) - numpy.float128(1)zwraca 0.0. Zobacz stackoverflow.com/a/29821557/420755
Jeff,
0.1 + 0.2 nie jest dokładną wartością 0.3 w Pythonie, w każdym innym języku jest to problem zmiennoprzecinkowy, ale nigdy podwójny. Dlaczego w Pythonie nie jest to dokładne 0,3?
Oprogramowanie Fusca
@FuscaSoftware To problem także w innych językach. Podwójne IEEE nie mogą dokładnie odpowiadać 0,3. To brzmi jak artefakt formatowania.
Hans Musgrave
17

W przypadku niektórych aplikacji możesz użyć Fractionzamiast liczb zmiennoprzecinkowych.

>>> from fractions import Fraction
>>> Fraction(1, 3**54)
Fraction(1, 58149737003040059690390169)

(W przypadku innych aplikacji jest decimal, jak sugerują inne odpowiedzi).

Gareth Rees
źródło
1
jak wybrać między dziesiętnym a ułamkowym? Ułamek wydaje się lepszy, ponieważ może reprezentować ciągłe ułamki, których, jak sądzę, Decimal nie może?
Janus Troelsen
1
@Janus: rozważ swoje wymagania i wybierz to, które lepiej do nich pasuje. Użyj, Decimalgdy chcesz pracować z przybliżonymi liczbami, które mają stałą (ale konfigurowalną) precyzję. Używaj, Fractiongdy chcesz pracować z dokładnymi stosunkami i jesteś przygotowany na sprostanie nieograniczonym wymaganiom dotyczącym przechowywania.
Gareth Rees
Czy Fraction obsługuje wszystkie operacje, które można wykonać za pomocą float?
danijar
14

Może potrzebujesz Decimal

>>> from decimal import Decimal    
>>> Decimal(2.675)
Decimal('2.67499999999999982236431605997495353221893310546875')

Arytmetyka zmiennoprzecinkowa

skoczek pustynny
źródło
1

Oto moje rozwiązanie. Najpierw tworzę losowe liczby za pomocą random.uniform, formatuję je do łańcucha z podwójną precyzją, a następnie konwertuję je z powrotem na zmiennoprzecinkowe. Możesz dostosować precyzję, zmieniając „.2f” na „.3f” itp.

import random
from decimal import Decimal

GndSpeedHigh = float(format(Decimal(random.uniform(5, 25)), '.2f'))
GndSpeedLow = float(format(Decimal(random.uniform(2, GndSpeedHigh)), '.2f'))
GndSpeedMean = float(Decimal(format(GndSpeedHigh + GndSpeedLow) / 2, '.2f')))
print(GndSpeedMean)
Bittikettu
źródło
1
Dobrze. Podwójna precyzja oznacza binarną reprezentację zmiennej o podwójnej długości w porównaniu z binarną reprezentacją zmiennej typu float. Nie dwa miejsca po przecinku.
kravemir
Masz rację. Mogłem użyć złych kryteriów wyszukiwania, kiedy sam miałem ten problem i to jest wynik. Inni mogą przeszukać ten sam problem, co ja i skończyć tutaj. Miejmy nadzieję, że znajdą jakąś ulgę. :)
Bittikettu
To najgorszy sposób, jaki przychodzi mi do głowy, aby zaokrąglić liczbę zmiennoprzecinkową do dwóch miejsc po przecinku. Powinieneś użyć przynajmniej numpy.floor(100*a)/100do skrócenia liczby ado dwóch miejsc po przecinku.
Wauzl