В приведенном вами примере кажется, что обе программы имеют одинаковые числа с плавающей запятой. Просто печатают по другому. Самое простое решение этой конкретной проблемы — написать собственную функцию печати с плавающей запятой. Если вы не ожидаете слишком хорошего результата, вы можете использовать функцию здесь как псевдокод для написания своего на C. Он не правильно округлен, но работает для того, для чего предназначен (то есть воспроизводим и читабелен выходы).
Более глубокая проблема, с которой вы столкнулись, — это вычисления с плавающей запятой, дающие разные результаты на разных платформах. Это результат того, что стандарт (стандарты) C не вынуждает компиляторы точно реализовывать стандарт IEEE 754 с плавающей запятой, в частности, обеспечивая более высокую точность для промежуточных результатов. И эта относительная снисходительность стандарта (стандартов) C вызвана, по крайней мере, частично историческими инструкциями x86 с плавающей запятой, что делает дорогостоящей реализацию точной семантики IEEE 754.
В Linux, если вы используете GCC, попробуйте вариант компиляции -msse2
. РЕДАКТИРОВАТЬ: ОП прокомментировал, что -msse2 -mfpmath=sse
работал на него. Это заставляет GCC генерировать современные инструкции SSE2, которые дают точную семантику IEEE 754 с плавающей запятой. Если в Windows вы также используете GCC, используйте ту же опцию.
Если вы используете Visual C: Visual C использует еще один трюк, чтобы заставить исторические инструкции с плавающей запятой соответствовать семантике IEEE 754: он сообщает старому 80-битному оборудованию с плавающей запятой использовать только столько значащих битов, сколько IEEE 754 двойной точности. имеет. Это дает точную симуляцию чисел с двойной точностью, за исключением нескольких крайних случаев, с которыми вы не столкнетесь. В этом случае было бы полезно (*), если бы ваша программа использовала только числа с двойной точностью (тип C double
).
(*) Компилятор Visual C теоретически мог бы генерировать код, который вычисляет точную арифметику с одинарной точностью, округляя каждый промежуточный результат от двойной до одинарной точности, но это было бы дорого, и я сомневаюсь, что он это делает.
person
Pascal Cuoq
schedule
26.11.2012
printf
используемых библиотек c различаются. Windows печатает только 17 значащих цифр или около того и заполняет нулями, если требуется больше. glibc печатает правильно округленное значение. - person Daniel Fischer   schedule 26.11.2012double
обычно имеет точность около 16 значащих десятичных цифр. Дальше печатать или сравнивать цифры бессмысленно. - person Blastfurnace   schedule 26.11.2012