#cpp #компиляция #float #double
По роду деятельности я был вынужден плотно работать с форматом IEEE-754, в процессе чего обнаружил, что ни один из известных мне компиляторов (VC++, Intel C++, CLang, GCC (именно MinGW)) не умеет конвертировать некоторые числа в десятичной записи (типа, 1.2345e67) в формат с плавающей точкой. Все компиляторы, что я проверял, падают на несложных тестах, когда неочевидным для компилятора является способ округления (вверх или вниз). Примеры таких тестов можно увидеть в этом cpp файле (код слишком длинный, чтобы постить сюда). Мой вопрос таков: знаете ли вы компилятор, который без ошибок пройдёт хотя бы эти простые тесты (все из этого файла)? Если таковой найдётся, я предоставлю более сложные тесты. Просто скомпилируйте и запустите программу, она выдаст на консоль, что пройдено, а что нет. Кто найдёт такой компилятор, прошу назвать его в ответе. Может быть кто-то захочет проверить работу тестов на других языках, буду рад узнать результат, только вам сначала придётся написать похожую программу на основе данных тестов. PS. Если же кому-то будет интересна причина падения, я объяснял её в одной из своих бесед (см. видео) UPD: Тесты против СLang (GCC их проходит). Предложенные тесты соответствуют стандарту языка C++ (длина строки и лексемы не превышает 65535 символов). У меня ещё есть несколько десятков тестов против CLang, которые рушат компилятор напрочь. Все связаны с long double (например, подайте ему на вход минимальное денормализованное число, он упадёт). Должен, однако, признать, что для float и double CLang действительно проходит все мои тесты, но часто выдаёт предупреждения при компиляции там, где не должен. В любом случае, данный компилятор также не поддерживает формат IEEE-754 полностью. UPD2: Тесты, которые валят CLang и не работают в GCC (MinGW). UPD3: Все тесты теперь на GitHub. Позже, когда у меня наступит ясность (или, быть может, кто-то найдёт у меня ошибки) по данному вопросу, я объединю всё в один файл для удобства.
Ответы
Ответ 1
Base Gcc 5.3.0, судя по всему прошёл: $ gcc TestIEEE754Convertion.cpp TestIEEE754Convertion.cpp:80:3: warning: floating constant truncated to zero [-Woverflow] -2.470328229206232720882843964341106861825e-324, ^ TestIEEE754Convertion.cpp:19:3: warning: anonymous type with no linkage used to declare variable ‘f32’ with linkage } f32; ^ TestIEEE754Convertion.cpp:25:3: warning: anonymous type with no linkage used to declare variable ‘ f64’ with linkage } f64; ^ $ ./a.out ::: Single precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 ::: Double precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 Right on test 8 Right on test 9 Right on test 10 Right on test 11 Right on test 12 Right on test 13 Right on test 14 Right on test 15 Right on test 16 Right on test 17 Right on test 18 Right on test 19 Right on test 20 Right on test 21 Right on test 22 Right on test 23 Gcc 4.8.5: $ ./a.out ::: Single precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 ::: Double precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 Right on test 8 Right on test 9 Right on test 10 Error on test 11: 0x7fefffffffffffff != 0x7feffffffffffffe Error on test 12: 0x7fefffffffffffff != 0x7feffffffffffffe Right on test 13 Right on test 14 Right on test 15 Right on test 16 Right on test 17 Right on test 18 Right on test 19 Error on test 20: 0x8000000000000000 != 0x8000000000000001 Right on test 21 Right on test 22 Right on test 23 Gcc 4.9.3: $ ./a.out ::: Single precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 ::: Double precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 Right on test 8 Right on test 9 Right on test 10 Right on test 11 Right on test 12 Right on test 13 Right on test 14 Right on test 15 Right on test 16 Right on test 17 Right on test 18 Right on test 19 Right on test 20 Right on test 21 Right on test 22 Right on test 23 Hard 2 Для UPD2 Gcc 5 тоже молодец: $ gcc TestIEEE754ConvertionHard2.cpp $ ./a.out OK Gcc 4.8.5 - ERROR, Gcc 4.9.3 - OK Hard 3 $ g++-5 -O0 ./TestIEEE754ConvertionHard3.cpp ./TestIEEE754ConvertionHard3.cpp:19:3: предупреждение: anonymous type with no linkage used to declare variable « f32» with linkage } f32; ^ ./TestIEEE754ConvertionHard3.cpp:25:3: предупреждение: anonymous type with no linkage used to declare variable « f64» with linkage } f64; ^ $ ./a.out ::: Double precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 Right on test 8 Судя по всему прошёл. Gcc 4.9 - аналогично. Gcc 4.8 сфейлил тесты 5, 7, 8 Strict aliasing Кстати, я могу что-то путать, но разве такие преобразования: #define TEST(HI, LO, F) f = F; if (*(((unsigned short int*)&f)+4) != HI || *(unsigned long long*)&f != LO) { printf ("ERROR"); return 1; } не нарушают правило strict-aliasing? Не, конечно -Wstrict-aliasing -fstrict-aliasing это место пропускает и код на рабочих компиляторах работает. Но как-то, малость, не по себе. Ответ 2
C# 6, судя по всему, прошёл. Адаптированный тест, MSVC 2015, выдаёт: ::: Single precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 ::: Double precision ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 Right on test 8 Right on test 9 Right on test 10 Right on test 11 Right on test 12 Right on test 13 Right on test 14 Right on test 15 Right on test 16 Right on test 17 Right on test 18 Right on test 19 Right on test 20 Right on test 21 Right on test 22 Right on test 23 ::: Double precision (TestIEEE754ConvertionHard3.cpp) ::: Right on test 0 Right on test 1 Right on test 2 Right on test 3 Right on test 4 Right on test 5 Right on test 6 Right on test 7 Right on test 8 Адаптированный исходник: class Program { // Тестирование числа одинарной точности void test32(float a, uint right, int testNumber) { var floatBytes = BitConverter.GetBytes(a); var uintValue = BitConverter.ToUInt32(floatBytes, 0); if (uintValue != right) Console.WriteLine($"Error on test {testNumber}: {uintValue:x8} != {right:x8}"); else Console.WriteLine($"Right on test {testNumber}"); } // Тестирование числа двойной точности void test64(double a, ulong right, int testNumber) { var ulongValue = (ulong)BitConverter.DoubleToInt64Bits(a); if (ulongValue != right) Console.WriteLine($"Error on test {testNumber}: {ulongValue:x16} != {right:x16}"); else Console.WriteLine($"Right on test {testNumber}"); } // Список чисел одинарной точности и правильных двоичных представлений этих чисел const int N32 = 8; float[] Test32 = new float[ N32 ] { 21267649200209254194690314461188718593.0f, 1.175494280757364291727882991035766513322e-38f, 1.175494280757364291727882991035766513323e-38f, 10749727.50000000000000000000000000000001f, 10749728.50000000000000000000000000000001f, -1.175494420887210724209590083408724842314e-38f, -1.175494420887210724209590083408724842315e-38f, -340282336497324057985868971510891282432.1f }; uint[] Right32 = new uint[ N32 ] { 0x7d800001, 0x007fffff, 0x00800000, 0x4b240720, 0x4b240721, 0x80800000, 0x80800001, 0xff7fffff }; // Список чисел двойной точности и правильных двоичных представлений этих чисел const int N64 = 24; double[] Test64 = new double[ N64 ] { -2.470328229206232720882843964341106861825e-324, -2.470328229206232720882843964341106861826e-324, 2.225073858507200641991763955462587799366e-308, 2.225073858507200641991763955462587799367e-308, 6755399441055826.499999999999999999999999, 6755399441055826.500000000000000000000001, 179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218944.1, 11417981541647677146990387413251858846007164927.9, 11417981541647677146990387413251858846007164928.0, 11417981541647677146990387413251858846007164928.1, 11417981541647677780815687527366559594358767616.0, 179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218943.9, 179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218944.0, 179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218944.1, 9214843084008499.0, 0.500000000000000166533453693773481063544750213623046875, 30078505129381147446200.0, 3.518437208883201171875e13, 8.10109172351e-10, 9007199254740991.4999999999999999999999999999999995, -2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324, 6755399441055827.499999999999999999999999, 6755399441055827.5, 6755399441055827.500000000000000000000001 }; ulong[] Right64 = new ulong[ N64 ] { 0x8000000000000000, 0x8000000000000001, 0x000ffffffffffffe, 0x000fffffffffffff, 0x4338000000000052, 0x4338000000000053, 0x7fefffffffffffff, 0x497ffffffffffffe, 0x497ffffffffffffe, 0x497fffffffffffff, 0x497fffffffffffff, 0x7feffffffffffffe, 0x7feffffffffffffe, 0x7fefffffffffffff, 0x43405e6cec57761a, 0x3fe0000000000002, 0x44997a3c7271b021, 0x42c0000000000002, 0x3e0bd5cbaef0fd0c, 0x433fffffffffffff, 0x8000000000000001, 0x4338000000000053, 0x4338000000000054, 0x4338000000000054 }; // Более сложный тест из https://github.com/Zealint/fp_tests/blob/master/TestIEEE754ConvertionHard3.cpp const int N64Hard = 9; double[] Test64Hard = new double[ N64Hard ] { 2.225073858507201383090232717332404064219215980462331830553327416887204434813918195854283159012511020564067339731035811005152434161553460108856012385377718821130777993532002330479610147442583636071921565046942503734208375250806650616658158948720491179968591639648500635908770118304874799780887753749949451580451605050915399856582470818645113537935804992115981085766051992433352114352390148795699609591288891602992641511063466313393663477586513029371762047325631781485664350872122828637642044846811407613911477062801689853244110024161447421618567166150540154285084716752901903161322778896729707373123334086988983175067838846926092773977972858659654941091369095406136467568702398678315290680984617210924625396728515625e-308, 2.2250738585072018771558785585789482407880088486837041956131300312119688603996006965297904292212628858639037013670281908017171296072711910355127227413175152199055740043138804567803233377539881639177387328959246074229270113078053813397081653361296447449529789521218979090783852583365901851789618799885150427514782636076021680436220311292700454832073964845713103912225963935608322440623896907276890186717054549275173986589324810401738228328251245795065655738191038008646911615828719989708647293221449796971546706720399791990809160347625980385995424739847678861180095072511543762389603716215171729816011544604359531284325406441938645324905389137795680915804792405099227413854274942620542640408839836919187418172987793340279242767544565229087538682506419718265533447265625e-308, 2.225073858507202371221524399825492417356801716905076560672932645536733285985283197205297699430014751163740063003020570598281825052988921962169433097257311618680370015095758583081036528065392691763555900744906711111645647364804112062758171723538798309937366264595295182248000398368305570577036006227080633922504922164288936230661591439894977428478987977026639696679140794688312373772389232659678427752122018252042155806801495766953982188063736129641369100312575820243717972293621169304087413797478551780397864281278268544917722045363748655580517781818995617950934297749406849316597964346304638590078974833882923081797242441461636291003104968899481242069589385613709015202152589845793237400783350172912858237869043043055848553508913045817507736501283943653106689453125e-308, 2.22507385850720163012305563795567615250361241457301801308322872404958664760675944619203679411688695321398552054903200090343478188441232557218436756334761702051817599892294139362996674259828589999483014897143355557856769327930601597818316214242506796246078529588519927249357768832073249247992481686923224716596493432925878395010225097395757951057160073834364573849432419299709217920738991976169431413149717326525502008499797367678374315520581880443916381057236779117517775622749741380425338708447819365553307386742083452616251302946202273010905482006765402020154711200202813970014157525912344017736224427371246815175018974555997865323425588621961151633592416795802960447706494647018477736093430045142168360701364747951396213837722826145437693412532098591327667236328125e-308, 2.22507385850720163012305563795567615250361241457301801308322872404958664760675944619203679411688695321398552054903200090343478188441232557218436756334761702051817599892294139362996674259828589999483014897143355557856769327930601597818316214242506796246078529588519927249357768832073249247992481686923224716596493432925878395010225097395757951057160073834364573849432419299709217920738991976169431413149717326525502008499797367678374315520581880443916381057236779117517775622749741380425338708447819365553307386742083452616251302946202273010905482006765402020154711200202813970014157525912344017736224427371246815175018974555997865323425588621961151633592416795802960447706494647018477736093430045142168360701364747951396213837722826145437693412532098591327667236328124999e-308, 2.22507385850720163012305563795567615250361241457301801308322872404958664760675944619203679411688695321398552054903200090343478188441232557218436756334761702051817599892294139362996674259828589999483014897143355557856769327930601597818316214242506796246078529588519927249357768832073249247992481686923224716596493432925878395010225097395757951057160073834364573849432419299709217920738991976169431413149717326525502008499797367678374315520581880443916381057236779117517775622749741380425338708447819365553307386742083452616251302946202273010905482006765402020154711200202813970014157525912344017736224427371246815175018974555997865323425588621961151633592416795802960447706494647018477736093430045142168360701364747951396213837722826145437693412532098591327667236328125001e-308, 2.22507385850720212418870147920222032907240528279439037814303133837435107319244194686754406432563881851382188218502438069999947733013005649884107791928741341929297200970481951993067993290969042784064731682041565926728632933630474670123316852983422152744517260835859654566319282835244787787799894310779783833699159288594555213714181128458251145584319223079897504395086859412457230891738946169368372321191373658977977723286698840356390251044443035457396733706583981055420456693824658413747607155981176573877626747665912387199931904006317334709003012790188175203447190250028061277777916798391090578584006464715943810511489154282775041174682194133952466682503431306181587829379004205392375072083366693241580002758391118854188641513168478436313080237596295773983001708984374999e-308, 2.22507385850720212418870147920222032907240528279439037814303133837435107319244194686754406432563881851382188218502438069999947733013005649884107791928741341929297200970481951993067993290969042784064731682041565926728632933630474670123316852983422152744517260835859654566319282835244787787799894310779783833699159288594555213714181128458251145584319223079897504395086859412457230891738946169368372321191373658977977723286698840356390251044443035457396733706583981055420456693824658413747607155981176573877626747665912387199931904006317334709003012790188175203447190250028061277777916798391090578584006464715943810511489154282775041174682194133952466682503431306181587829379004205392375072083366693241580002758391118854188641513168478436313080237596295773983001708984375e-308, 2.22507385850720212418870147920222032907240528279439037814303133837435107319244194686754406432563881851382188218502438069999947733013005649884107791928741341929297200970481951993067993290969042784064731682041565926728632933630474670123316852983422152744517260835859654566319282835244787787799894310779783833699159288594555213714181128458251145584319223079897504395086859412457230891738946169368372321191373658977977723286698840356390251044443035457396733706583981055420456693824658413747607155981176573877626747665912387199931904006317334709003012790188175203447190250028061277777916798391090578584006464715943810511489154282775041174682194133952466682503431306181587829379004205392375072083366693241580002758391118854188641513168478436313080237596295773983001708984375001e-308 }; ulong[] Right64Hard = new ulong[ N64Hard ] { 0x0010000000000000, 0x0010000000000001, 0x0010000000000002, 0x0010000000000000, 0x0010000000000000, 0x0010000000000001, 0x0010000000000001, 0x0010000000000002, 0x0010000000000002 }; static void Main(string[] args) { new Program().Run(); } void Run() { // Проверка всех чисел одинарной точности в цикле Console.WriteLine("\n\n::: Single precision :::\n"); for (int i = 0; i < N32; i++) test32(Test32[i], Right32[i], i); // Проверка всех чисел двойной точности в цикле Console.WriteLine("\n::: Double precision :::\n"); for (int i = 0; i < N64; i++) test64(Test64[i], Right64[i], i); // Более сложная проверка (TestIEEE754ConvertionHard3.cpp) Console.WriteLine("\n::: Double precision (TestIEEE754ConvertionHard3.cpp) :::\n"); for (int i = 0; i < N64Hard; i++) test64(Test64Hard[i], Right64Hard[i], i); } } Обновление: тесты с long double перенести на C# не получится, т. к. аналога типа данных long double (80 бит с плавающей запятой) в .NET текущей версии нету. Обновление: добавил тесты из https://github.com/Zealint/fp_tests/blob/master/TestIEEE754ConvertionHard3.cppОтвет 3
gcc 4.9.2 вроде проходит. На всех четырёх. Везде "Right on" и "OK".
Комментариев нет:
Отправить комментарий