Проблемы портирования плавающей точки на 64 бита

Если вы хотите вычесть количество дней и отформатировать дату в удобочитаемом формате, вам следует рассмотреть возможность создания пользовательского объекта DateHelper, который выглядит примерно так:

var DateHelper = {
    addDays : function(aDate, numberOfDays) {
        aDate.setDate(aDate.getDate() + numberOfDays); // Add numberOfDays
        return aDate;                                  // Return the date
    },
    format : function format(date) {
        return [
           ("0" + date.getDate()).slice(-2),           // Get day and pad it with zeroes
           ("0" + (date.getMonth()+1)).slice(-2),      // Get month and pad it with zeroes
           date.getFullYear()                          // Get full year
        ].join('/');                                   // Glue the pieces together
    }
}

// With this helper, you can now just use one line of readable code to :
// ---------------------------------------------------------------------
// 1. Get the current date
// 2. Subtract 5 days
// 3. Format it
// 4. Output it
// ---------------------------------------------------------------------
document.body.innerHTML = DateHelper.format(DateHelper.addDays(new Date(), -5));

(см. Также эту скрипку )

6
задан mskfisher 11 May 2012 в 13:40
поделиться

9 ответов

Нет необходимости, чтобы числа с плавающей запятой и удвоения вели себя по-разному в 32-битном и 64-битном коде, но часто это так. Ответ на ваш вопрос будет зависеть от платформы и компилятора, поэтому вам нужно указать, с какой платформы вы переносите и на какую платформу вы переноситесь.

На платформах Intel x86 32-битный код часто использует сопроцессор x87 набор команд и стек регистров с плавающей запятой для максимальной совместимости, тогда как на платформах amb64 / x86_64 вместо них часто используются инструкции SSE * и регистры xmm *. У них разные характеристики точности.

Редактирование сообщения:

Учитывая вашу платформу, вы можете попробовать использовать -mfpmath = 387 (значение по умолчанию для i386 gcc) в вашей сборке x86_64, чтобы увидеть, объясняет ли это разные результаты.

8
ответ дан 8 December 2019 в 04:09
поделиться

Ваш компилятор, вероятно, использует коды операций SSE для выполнения большей части своей арифметики с плавающей запятой на 64-битной платформе, предполагающей x86-64, тогда как по соображениям совместимости он, вероятно, раньше использовал FPU для большей части своих операции.

Коды операций SSE предлагают намного больше регистров и единообразия (значения всегда остаются 32-битными или 64-битными), тогда как FPU по возможности использует 80-битные промежуточные значения. Таким образом, вы, скорее всего, раньше извлекали выгоду из этой улучшенной промежуточной точности. (Обратите внимание, что дополнительная точность может привести к непоследовательным результатам, например x == y, но cos (x)! = Cos (y), в зависимости от того, насколько далеко друг от друга происходят вычисления!)

Вы можете попробовать использовать -mfpmath = 387 для ваших 64 битовая версия, поскольку вы компилируете с помощью gcc, и посмотрите, совпадают ли ваши результаты с 32-битными результатами, чтобы сузить круг вопросов.

10
ответ дан 8 December 2019 в 04:09
поделиться

Как уже говорили другие, вы не предоставили достаточно информации, чтобы точно сказать, что происходит. Но в общем смысле кажется, что вы рассчитывали на какое-то поведение с плавающей запятой, на которое не следует рассчитывать.

В 99 случаях из 100 проблема в том, что вы где-то сравниваете два числа с плавающей запятой. .

Если проблема заключается просто в том, что вы получаете несколько разные ответы, вы должны понимать, что ни один ни один из них не является «правильным» - какое-то округление будет иметь место, несмотря ни на что. архитектура, на которой вы находитесь. Это вопрос понимания значащих цифр в ваших расчетах и ​​осознания того, что любые значения, которые вы придумываете, в определенной степени являются приблизительными.

3
ответ дан 8 December 2019 в 04:09
поделиться

80-битные внутренние регистры FPU x87 приводят к тому, что его результаты с плавающей запятой немного отличаются от других FPU, которые используют 64-битные внутренние регистры (как на x86_64). Вы получите разные результаты между этими процессорами, если только вы не будете возражать против значительного снижения производительности, сбрасывая данные в память или выполняя другие уловки "strictfp".

См. Также: Округление с плавающей запятой при усечении

И: http://docs.sun.com/source/806-3568/ncg_goldberg.html

3
ответ дан 8 December 2019 в 04:09
поделиться

В x64 используется набор инструкций SSE2, а в 32-разрядных приложениях по умолчанию часто используется FPU x87.

Последний внутренне сохраняет все значения с плавающей запятой в 80-битном формате. Последний использует простые 32-битные числа с плавающей запятой IEEE.

Кроме того, важно отметить, что вы не должны полагаться на то, что ваши вычисления с плавающей запятой идентичны для разных архитектур .

Даже если вы используете 32-битные сборки на обеих машинах , все еще нет гарантии, что Intel и AMD дадут одинаковые результаты. Конечно, когда один из них запускает 64-битную сборку, вы только добавляете больше неопределенности.

Полагаться на точные результаты операций с плавающей запятой почти всегда было бы ошибкой.

Включение SSE2 в 32-битной версии также было бы хорошим началом, но опять же, не делайте предположений относительно кода с плавающей запятой.

2
ответ дан 8 December 2019 в 04:09
поделиться

Компилятор GNU имеет множество опций компилятора, связанных с числами с плавающей запятой, которые при некоторых обстоятельствах могут привести к прерыванию вычислений. Просто поищите на этой странице по запросу "float", и вы найдете их.

0
ответ дан 8 December 2019 в 04:09
поделиться

Очень сложно контролировать многие из этих вещей.

Для начала, стандарт C часто требует, чтобы операции с числами с плавающей запятой выполнялись в "двойном пространстве" и преобразовывались обратно в с плавающей запятой.

У процессоров Intel точность регистров составляет 80 бит, которые они используют для многих из этих операций, а затем они понижают ее до 64 бит при сохранении в основной памяти. Это означает, что значение переменной может измениться без видимой причины.

Вы можете использовать такие вещи, как GnuMP, если вам действительно интересно, и я уверен, что есть и другие библиотеки, которые гарантируют согласованные результаты. В большинстве случаев количество генерируемых ошибок / джиттера ниже реального разрешения, которое вам нужно.

0
ответ дан 8 December 2019 в 04:09
поделиться

На самом деле сложно получить то, что оба набора результатов верны. Было бы несправедливо характеризовать изменения как что-либо, кроме «других». Возможно, есть повышенная эмоциональная привязанность к более старым результатам ... но нет математической причины предпочитать 32-битные результаты 64-битным результатам.

Рассматривали ли вы возможность использования математики с фиксированной запятой в этом приложении? Математика с фиксированной запятой не только стабильна при изменении микросхемы, компилятора и библиотек, но и во многих случаях быстрее, чем математика с плавающей запятой.

В качестве быстрой проверки переместите двоичный файл из 32-битной системы в 64-битную систему и запустите его. Затем перестройте приложение в 64-битной системе как 32-битный двоичный файл и запустите его. Это может помочь определить, какие изменения на самом деле вызывают расхождение в поведении.

0
ответ дан 8 December 2019 в 04:09
поделиться

Как уже упоминалось, отличия не должны быть проблемой, если они оба верны. В идеале у вас должны быть модульные тесты для такого рода вещей (чистые вычисления обычно относятся к относительно легкому для тестирования лагерю).

По сути невозможно гарантировать одинаковые результаты для ЦП и инструментальных цепочек (один флаг компилятора может сильно изменить уже), и уже очень трудно быть последовательным. Разработка надежного кода с плавающей запятой - сложная задача, но, к счастью, во многих случаях точность не является проблемой.

0
ответ дан 8 December 2019 в 04:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: