Jaka jest różnica między twardymi a miękkimi liczbami zmiennoprzecinkowymi?


98

Kiedy kompiluję kod C z moim krzyżowym łańcuchem narzędzi, linker drukuje strony z ostrzeżeniami, mówiąc, że mój plik wykonywalny używa twardych pływaków, ale moja biblioteka libc używa miękkich pływaków. Co za różnica?


Jeśli jest to architektura ARM, umieść to w tagach :-)
— Nils Pipenbrinck

3
@Nils Pipenbrinck: Chipy MIPS również mają ten problem
— Javier

Odpowiedzi:


100

Twarde spławiki używają wbudowanej jednostki zmiennoprzecinkowej. Miękkie pływaki emulują je w oprogramowaniu. Różnica polega na szybkości. Dziwne jest to, że oba są używane w tej samej architekturze docelowej, ponieważ chip albo ma FPU, albo go nie ma. Możesz włączyć miękki zmiennoprzecinkowy w GCC za pomocą -msoft-float. Możesz chcieć przekompilować swoją bibliotekę libc, aby używała sprzętowych wartości zmiennoprzecinkowych, jeśli jej używasz.


3
„Dziwnie jest widzieć oba używane w tej samej architekturze docelowej”. Może to mieć sens dla biblioteki, aby była niezależna od maszyny i dokładna bitowo (miękki ruch zmienny) w częściach krytycznych dla dokładności i szybka (twarda) w częściach, w których niewielkie odchylenia nie to ma znaczenie.
— PhilLab

Dzieje się tak na 32-bitowym ARM.
— Aaron Franke

31

Istnieją trzy sposoby wykonywania arytmetyki zmiennoprzecinkowej:

  • Użyj instrukcji float, jeśli twój procesor ma FPU. (szybki)
  • Niech twój kompilator przetłumaczy arytmetykę zmiennoprzecinkową na arytmetykę liczb całkowitych. (powolny)
  • Użyj instrukcji float i procesora bez FPU. Twój procesor wygeneruje wyjątek (instrukcja zastrzeżona, instrukcja niezaimplementowana lub podobny), a jeśli jądro twojego systemu operacyjnego zawiera emulator zmiennoprzecinkowy, będzie emulować te instrukcje (najwolniej).

23

Ściśle mówiąc, wszystkie te odpowiedzi wydają mi się błędne.

Kiedy kompiluję kod C z moim krzyżowym łańcuchem narzędzi, linker drukuje strony z ostrzeżeniami, mówiąc, że mój plik wykonywalny używa twardych pływaków, ale moja biblioteka libc używa miękkich pływaków. Co za różnica?

Debian VFP wiki zawiera informacje o trzech opcjach -mfloat-abi:

  • soft - to jest czyste oprogramowanie
  • softfp- obsługuje sprzętową FPU, ale ABI jest kompatybilny programowo.
  • hard- ABI używa rejestrów typu float lub VFP .

Błąd konsolidatora (programu ładującego) jest spowodowany tym, że masz bibliotekę współdzieloną, która przekazuje wartości zmiennoprzecinkowe w rejestrach całkowitych. Nadal możesz skompilować swój kod za pomocą a -mfpu=vfp, etc, ale powinieneś użyć -mfloat-abi=softfp, aby jeśli biblioteka libc wymagała float, jest przekazywana w sposób zrozumiały dla biblioteki.

Jądro Linuksa może obsługiwać emulację instrukcji VFP. Oczywiście -mfpu=nonew tym przypadku lepiej jest skompilować się, a kompilacja generuje kod bezpośrednio, zamiast polegać na emulacji jądra Linuksa. Jednak nie sądzę, aby błąd OP był faktycznie związany z tym problemem. Jest oddzielny i należy go również rozwiązać wraz z plikiem -mfloat-abi.

Biblioteka współdzielona Armv5 z procesorem ArmV7 jest przeciwieństwem tej; libc była ciężka pływak ale wniosek był tylko miękkie . Ma kilka sposobów obejścia tego problemu, ale rekompilacja z poprawnymi opcjami jest zawsze najłatwiejsza.

Inną kwestią jest to, że jądro Linuksa musi obsługiwać zadania VFP (lub jakikolwiek inny zmiennoprzecinkowy ARM), aby zapisać / przywrócić rejestry po przełączeniu kontekstu.


1
Nowoczesne wersje GCC (~ 4.8 +) obsługują „multi-lib”, które mają biblioteki hard float i soft float. Wcześniejsze wersje wymagały posiadania kompilatora zbudowanego w określonej wersji. Czasami ścieżka do właściwej biblioteki jest potrzebna podczas łączenia z dystrybucją gcc „multi-lib”, ponieważ istnieje kilka wersji bibliotek (wymaga więcej czasu na zbudowanie kompilatora). Nazwy katalogów mogą być „hf”, „hardf”, „libhf” lub „hard-float”, ale zwykle znajdują się one w zwykłym katalogu „soft” lub w pobliskiej lokalizacji.
— bezartowy hałas

To jest właściwa odpowiedź. Konwersja wywołań dla elementów zmiennoprzecinkowych musi być zgodna między kodem a biblioteką libc. Może nadal działać z niedopasowaniem, jeśli nigdy nie wywołasz żadnej zmiennoprzecinkowej funkcji libc.
— Tor Klingberg

13

Wygląda na to, że libc zostało zbudowane do programowych operacji zmiennoprzecinkowych, podczas gdy twój exe został skompilowany przy założeniu sprzętowej obsługi zmiennoprzecinkowej. W krótkiej perspektywie możesz wymusić miękkie pływaki jako flagę kompilatora. (jeśli używasz gcc, myślę, że to -msoft-float)

W dłuższej perspektywie, jeśli procesor twojego celu obsługuje sprzętową obsługę operacji zmiennoprzecinkowych, generalnie będziesz chciał zbudować lub znaleźć krzyżowy łańcuch narzędzi z włączoną sprzętową funkcją float dla zwiększenia szybkości. Niektóre rodziny procesorów mają warianty modeli, niektóre ze wsparciem sprzętowym, a niektóre bez. Na przykład samo stwierdzenie, że procesor jest ARM, nie wystarczy, aby wiedzieć, czy masz sprzętową obsługę liczb zmiennoprzecinkowych.


8

Obliczenia można wykonać za pomocą sprzętu zmiennoprzecinkowego lub oprogramowania opartego na arytmetyce liczb całkowitych.

Robienie tego na sprzęcie jest znacznie szybsze, ale wiele mikrokontrolerów nie ma sprzętu zmiennoprzecinkowego. W takim przypadku możesz albo uniknąć używania zmiennoprzecinkowych opcji (zazwyczaj jest to najlepsza opcja), albo polegać na implementacji w oprogramowaniu, które będzie częścią biblioteki C.

W niektórych rodzinach kontrolerów, na przykład ARM, sprzęt zmiennoprzecinkowy jest obecny w niektórych modelach z rodziny, ale nie w innych, więc gcc dla tych rodzin obsługuje oba. Twój problem polega na tym, że pomieszałeś te dwie opcje.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.