Typy zmiennoprzecinkowe o stałym rozmiarze

92

W nagłówkach stdint.h(C99), boost / cstdint.hpp i cstdint(C ++ 0x) znajduje się między innymi typ int32_t.

Czy istnieją podobne typy zmiennoprzecinkowe o stałym rozmiarze? Coś jak float32_t?

Pietro
źródło
4
Dlaczego potrzebujesz czegoś takiego?
ARAK
41
Potrzebujesz czegoś takiego, gdy masz strukturę danych z wartością zmiennoprzecinkową, a także chcesz dokładnie wiedzieć, jaki jest jej rozmiar.
mob
5
@mobrule: Jeśli chcesz tylko wiedzieć, jaki jest rozmiar, użyj sizeofoperatora. Taki typ byłby przydatny, gdy algorytm wymaga, aby był to znany określony rozmiar.
Stephen Canon
6
@Stephen Canon - tak, jeśli chcesz zagwarantować, jaki jest rozmiar. Powiedzmy, że instancja twojej struktury danych zmieści się w 64 bitach i może być przekazana według wartości do jakiejś zewnętrznej biblioteki.
mob
7
@StephenCanon Rozważmy wieloplatformową bibliotekę serializacji. W jaki sposób można sizeofrozwiązać problem konsekwentnego krosowania i niesprawdzania typów pływających?
Kyle Strand

Odpowiedzi:

47

Obecnie nic takiego nie istnieje w standardach C lub C ++. W rzeczywistości nie ma nawet gwarancji, że w floatogóle będzie binarnym formatem zmiennoprzecinkowym.

Niektóre kompilatory gwarantują, że floattypem będzie 32-bitowy format binarny IEEE-754. Niektórzy nie. W rzeczywistości floatjest to w rzeczywistości singletyp IEEE-754 na większości platform niezintegrowanych, chociaż mają zastosowanie zwykłe zastrzeżenia dotyczące niektórych kompilatorów oceniających wyrażenia w szerszym formacie.

Istnieje grupa robocza omawiająca dodanie powiązań języka C w wersji 2008 IEEE-754, która mogłaby rozważyć zalecenie dodania takiego typu. Gdyby to zostało dodane do C, spodziewam się, że standard C ++ pójdzie w ich ślady ... w końcu.

Stephen Canon
źródło
3
Niezależnie od IEEE-754 czy nie, nadal nie zapobiegnie to problemom z przenośnością Endian.
Mark B
1
@Pietro: zmiana języka nie wpłynie na zgodność sprzętu, a jedynie wykluczy zgodność niektórych urządzeń. W jaki sposób IEEE FP gwarantuje przenośność?
Potatoswatter
1
@Potatoswatter: Zachęciłoby to dostawców sprzętu do dostarczania zgodnych rozwiązań. Jeśli część a obsługuje standardowe C bez konieczności stosowania hacków biblioteki soft-float, a część b nie, to jest to przewaga rynkowa dla części a.
Stephen Canon
2
@Potatoswatter: (Prawie) nikt nie dba o szybkość sprzętu. Dbamy o szybkość działania oprogramowania na sprzęcie. Oprogramowanie może być szybsze, jeśli sprzęt, na którym działa, jest zgodny ze standardami, a oprogramowanie nie musi wykrywać i naprawiać 15 różnych przypadków specjalnych, w zależności od platformy, na której jest uruchomione.
Stephen Canon
8
Jak, u licha, można uzyskać lepszą przenośność, zapobiegając kompilacji kodu na wielu niszowych architekturach? Albo polegasz na elementach pływających będących IEEE, w którym to przypadku twój kod będzie już działał w każdej implementacji zgodnej z IEEE i na niczym innym, albo nie, w takim przypadku twój kod będzie działał w szerszym zakresie systemów. Gdyby C ++ gwarantował zgodność ze standardem IEEE, Twój kod w magiczny sposób nie stałby się bardziej przenośny, po prostu wykluczyłbyś, że mógłby kiedykolwiek działać na tych niezgodnych architekturach. Twoja logika jest całkowicie wsteczna.
jalf
30

Jeśli chcesz wiedzieć, czy floatjest to 32-bitowy typ IEEE, sprawdź std::numeric_limits<float>::is_iec559. To stała czasu kompilacji, a nie funkcja.

Jeśli chcesz być bardziej kuloodporny, sprawdź również, czy std::numeric_limits<float>::digitsnie podstępnie używają standardu podwójnej precyzji IEEE dla float. Powinno być 24.

Jeśli chodzi o long doubleto, ważniejsze jest sprawdzenie, digitsponieważ istnieje kilka formatów IEEE, którymi może być: 128 bitów (cyfry = 113) lub 80 bitów (cyfry = 64).

Nie byłoby to praktyczne float32_t, ponieważ zwykle chcesz używać sprzętu zmiennoprzecinkowego, jeśli jest dostępny, i nie polegać na implementacji oprogramowania.

Potatoswatter
źródło
long doubleFormat na OS X (zarówno 32-bit i 64-bit Intel) jest dokładnie IEEE-754 podwójny format rozszerzony przechowywane w ostrokońcej kolejności. Nie ma w tym nic dziwnego. Bajty 0-7 zawierają pole istotności, a bajty 8 i 9 zawierają wykładnik i pola znaku.
Stephen Canon
@Stephen: to dobra wiadomość: v). Czy zgadza się to z opublikowanymi przeze mnie liczbami?
Potatoswatter
1
Pamiętaj, że podwójnie rozszerzone (w przeciwieństwie do innych formatów 754) ma wyraźne znaczenie wiodące, więc 5.0Lma znaczenie a000000000000000. Jego nieobciążony wykładnik wynosi +2, a podwójny rozszerzony wykładnik wynosi 3fff, więc obciążony wykładnik dla 5,0L wynosi 4001. Rzeczywisty wzorzec bajtów przechowywany w kolejności little-endian to 00 00 00 00 00 00 00 a0 01 40, a jeśli zobaczysz to jako dwie 64-bitowe liczby całkowite little-endian, zobaczysz dokładnie to, co zaobserwowałeś.
Stephen Canon,
(*) podwójnie rozszerzony, jak zaimplementowano sprzętowo przez firmę Intel, to znaczy. Podwójnie rozszerzony format nie jest w rzeczywistości przypięty tak, jak pozostałe dwa podstawowe formaty IEEE-754 (1985).
Stephen Canon
@Stephen: Jestem prawie pewien, że 4001w little-endian jest 01 40 00 00 ...Jeśli nic innego, najmniej znaczący bajt jest pierwszy. Spodziewam się, że sekwencja a0 01 40pojawi się gdzieś w numerze (jeśli wykonali tylko rotację), ale nie sądzę, że wyjaśniłeś dlaczego a0i 01 40jesteś w całkowicie oddzielnych połówkach.
Potatoswatter
18

Jeśli uważasz, że posiadanie takich typów jak float32_t i float64_t jest niepraktyczne z jakichkolwiek powodów, musisz być zbyt przyzwyczajony do swojego znajomego systemu operacyjnego, kompilatora, że ​​nie możesz zbytnio wyjrzeć poza swoje małe gniazdo.

Istnieje sprzęt, który natywnie obsługuje 32-bitowe operacje zmiennoprzecinkowe IEEE i inne, które wykonują 64-bitowe. Czasami takie systemy muszą nawet ze sobą rozmawiać, w takim przypadku niezwykle ważne jest, aby wiedzieć, czy double jest 32-bitowy, czy 64-bitowy na każdej platformie. Jeśli platforma 32-bitowa miałaby wykonywać nadmierne obliczenia w oparciu o wartości 64-bitowe z drugiej, możemy chcieć rzucić na niższą precyzję w zależności od wymagań dotyczących czasu i prędkości.

Osobiście czuję się nieswojo używając pływaków i podwójnych, chyba że wiem dokładnie, ile bitów znajduje się na mojej platformie. Tym bardziej, jeśli mam je przenieść na inną platformę przez jakiś kanał komunikacyjny.

EmbeddedCoder
źródło
„Osobiście czuję się nieswojo używając pływaków i podwójnych, chyba że wiem dokładnie, ile bitów znajduje się na mojej platformie. Tym bardziej, jeśli mam przenieść je na inną platformę przez jakiś kanał komunikacyjny”. - Masz na myśli, że używasz formatów plików tekstowych? Z nimi wynika wada rozmiaru pliku: 32 zmiennoprzecinkowy wymaga 4 bajtów; te w formie tekstowej mogą przedstawiać tylko czterocyfrową liczbę ...
Pietro
3

Obecnie istnieje propozycja dodania następujących typów do języka:

decimal32
decimal64
decimal128

które pewnego dnia mogą być dostępne za pośrednictwem #include <decimal>.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3871.html

Trevor Hickey
źródło
3
To prawda, że ​​typy dziesiętne nie są typami zmiennoprzecinkowymi IEEE 754.
Mike DeSimone