2013-11-16 4 views
1

Я знаю, что переменные с плавающей запятой теряют точность при кастинге. Но я не понимаю, почему приведение от более мелкого примитива к большему неточно, но наоборот. Я бы понял, если это происходит от двойного к плаванию, но все наоборот. Почему это так?Почему float для двойного литья нечеткой, двойной, чтобы плавать?

Посмотреть результаты этих двух тестов:

@Test 
public void castTwoPrimitiveDecimalsUnpreciseToPrecise() 
{ 
    float var1 = 6.2f; 
    double var2 = var1; 

    assertThat(var2, is(6.2d)); //false, because it's 6.199999809265137 
} 

@Test 
public void castTwoPrimitiviesDecimalsPreciseToUnpresice() 
{ 
    double var1 = 7.6d; 
    float var2 = (float)var1; 

    assertThat(var2, is(7.6f)); //true 
} 
+6

Проблема в том, что ни один из номеров, которые вы используете, фактически * 6.2 или 7.6 ... –

+1

Но некоторые из них более отличаются от 6.2 и 7.6, чем другие. –

ответ

7

Точность проблема в инициализации ваших переменных, а не в процессе преобразования.

В первом случае вы начинаете с числа, которое является только приближением с поплавком к десятичной дробной 6.2. Преобразование в double получает двойное значение с точно таким же значением, как и с поплавковым приближением. Затем вы сравниваете его с гораздо более близким двойным приближением, поэтому, конечно, это не соответствует.

Во втором случае вы начинаете с двойного приближения десятичным числом 7.6. Затем вы конвертируете его в float. Это будет вокруг двойника до плавания. Округление дважды, при первоначальном преобразовании в двойное и на литье, чтобы плавать, могло бы создать другой ответ от прямого преобразования числа в float, но обычно вы получите приближение поплавка. Затем вы сравниваете его с приближением поплавка, поэтому неудивительно, что вы получаете совпадение.

1

Пусть кто-то измеряет спесь с линейкой и определяет, что/с диаметром 3/8" дюйма. Другой человек измеряет отверстие с суппортами и обнаруживает, что это 9.5267mm. Будет ли колышек поместиться в отверстие?

Если кто-то преобразует грубое измерение в форму с более высокой точностью, обнаруживается, что отверстие кажется 0.0017 мм (т. Е. Около 1/15000 ") больше, чем привязка. Если один из них преобразует их в форму с низкой точностью, то обнаружится, что значения неотличимы.

Если привязка, которая была измерена как 3/8 ", на самом деле точно равна 9,525 мм [точный метрический эквивалент], такое измерение может быть преобразовано в форму с более высоким разрешением без потерь преобразования. Если, однако, это просто означает «что-то, что ближе к знаку 3/8», чем к значению 23/64 или 25/64 », такое преобразование приведет к тому, что, как правило, ожидается, что приближение будет интерпретироваться как более точное, чем оно действительно .

Некоторые люди считают, что привязка и отверстие считаются разными по размеру, как хорошее. Лично я считаю, что было бы лучше рассматривать их как неотличимые. С измерениями, как описано, есть нет никаких оснований полагать с уверенностью, что привязка больше, чем дыра; это, вероятно, не совсем одинаково, но называть их неразличимыми точнее, чем говорить, что привязка больше.

Лично я ненавижу языковые правила, которые требуют, чтобы значения были записаны или отлиты для float [single-precision] только для того, чтобы заткнуть компилятор. Если один хочет установить float равным значению ближайшего к 4.7, один должен быть в состоянии просто сказать:

float f=4.7; 

и добиться этого эффекта. Человек, который видит:

static final float coef = 4.7f; 
... some time later 
float f = coef; 
double d = coef; 

не будет иметь никакого способа узнать, была ли цель установить d к значению double равного значению ближайшего float до 4,7, или была ли цель установить d к значению double ближайший к 4.7.К сожалению, Java не предоставляет никаких средств, с помощью которых можно объявить константу, которую можно без помех присвоить float без явного приведения в действие, но при назначении double будет использовать точность, доступную в этом типе.

Кстати, если моя цель состояла в том, чтобы установить некоторые double переменной v равным значению из float ближе к указанному числовому значению coef, а не значению double ближе всего к этому числовому значению, я бы, вероятно, его код очень явно:

v = (double)(float)coef; 

Это сделало бы ясным и недвусмысленным тот факт, что программист ожидавшую и намеревающиеся что double будет присвоено значение, которое было ранее округляется до float точности. Если нет (double) typecast, нужно было бы рассмотреть возможности, которые программист мог ожидать v как float (например, поскольку, когда код был написан, это был float, но с тех пор он был изменен на double). Если нетtypecast, нужно было бы рассмотреть возможность того, что программист ожидал, что coef будет double (например, потому что это было, но кто-то изменил его на float, чтобы он мог быть присвоен переменным типа float без компилятора кудахтанье).

Смежные вопросы