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?

Evan Kroske
źródło
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.

nmichaels
źródło
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).
ninjalj
źródło
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.

nieszlachetny hałas
źródło
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.

Digikata
źródło
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.

starblue
źródło