Подтвердить что ты не робот

Float to Double conversion - лучшее утверждение в unit test?

Учитывая утверждения

float f = 7.1f;
double d = f;

Что мы можем утверждать в unit test о d?


Например, это не работает:

Console.WriteLine(d == 7.1d); // false
Console.WriteLine(d < 7.1d + float.Epsilon); // true by luck
Console.WriteLine(d > 7.1d - float.Epsilon); // false (less luck)

Лучший способ, который я нашел до сих пор, - это преобразовать значение обратно:

float f2 = (float)d;
Console.WriteLine(f2 == f); // true

Который был бы таким же, как грубый способ сказать

Console.WriteLine(d == 7.1f); // 7.1f implicitly converted to double as above

Этот вопрос НЕ о двойной и плавающей точности в целом, но действительно JUST о прагматичном вопросе о том, как unit test лучше всего описать границы d. В моем случае d является результатом преобразования, которое происходит в коде, генерируемом генерацией легкого кода. При тестировании этого генерации кода я должен делать утверждения об исходе этой функции, и это, наконец, сводится к простому вопросу выше.

4b9b3361

Ответ 1

В вашем "наилучшем способе" утверждается, что ваш сгенерированный код возвращает что-то, что находится в пределах погрешности float, 7.1. Это может быть то, что вы хотите проверить, и в этом случае продолжайте.

С другой стороны, вы можете утверждать, что ваш сгенерированный код возвращает конкретный результат литья 7.1f в double, и в этом случае вы могли бы сделать:

Console.WriteLine(d == (double)f);

Это более жестко - ваш тест утверждает, что d находится в пределах небольшого диапазона, в то время как вышеупомянутый тест утверждает, что d является конкретным значением.

Это действительно зависит от того, для чего вы будете использовать d for. Если это случай, когда что-то пойдет не так, если это не точное значение, проверьте точное значение, но если он ОК, чтобы быть в пределах float от значения, проверьте на float.

Ответ 2

Чтобы сравнить два значения точки плавающей запятой ibm sugests для тестирования abs(a/b - 1) < epsilon

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

так что вы должны проверить

Math.Abs(d/(double)f) - 1) < float.Epsilon)

Ответ 3

(float) d == f.

Другой ответ предложил d == (double) f, но это бесполезный тест, потому что (double) f выполняет то же самое преобразование, которое d = f выполняет неявно. Таким образом, единственное, что может быть проверено этим утверждением, заключается в том, нарушен ли какой-либо аспект реализации (например, компилятор реализовал одну из преобразований неправильно и иным образом отличается от другой), какой-то внешний механизм изменил d или f между присваиванием и утверждением, или исходный код был сломан, так что d не был ни double, ни float, ни любым типом, который мог бы удерживать значение f в точности или назначение d = f не выполнялось.

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

Вместо этого мы конвертируем из более широкого формата обратно в более узкий формат. Если d отличается от f, это преобразование имеет шанс обнаружить ошибку. Например, предположим, что f содержит 0x1p-1000, но по какой-то причине он не представлен в формате d, поэтому он был округлен до нуля. Затем (float) d == f оценивается до (float) 0 == 0x1p-1000, затем до 0 == 0x1p-1000, затем до false. Кроме того, этот тест может обнаруживать те же ошибки, что и другое предложение: сломанная реализация, изменение d или f, неправильный тип d и отсутствие назначения d = f.

Кроме того, какие ошибки вы пытаетесь обнаружить с помощью утверждения здесь?