Целочисленное деление: как вы производите двойник?


для этого блока кода:

int num = 5;
int denom = 7;
double d = num / denom;

значение d и 0.0. Его можно заставить работать путем литья:

double d = ((double) num) / denom;

но есть ли другой способ получить правильный double результат? Я не люблю кастинг примитивов, кто знает, что может случиться.

10 194

10 ответов:

double num = 5;

это позволяет избежать приведения. Но вы обнаружите, что преобразования приведения четко определены. Вам не нужно угадывать, просто проверьте JLS. int to double-это расширяющееся преобразование. От §5.1.2:

расширяющегося примитивного преобразования не потерять информацию об общем величина числового значения.

[...]

преобразование значения int или long чтобы плавать, или длинное значение двойной, может привести к потере точность-то есть, результат может потерять некоторые из наименее значимых битов значение. В этом случае получается значение с плавающей запятой будет правильно округленная версия целочисленное значение, используя IEEE 754 круглый-ближайший режим (§4.2.4).

5 может быть выражено точно как двойной.

что не так с кастингом примитивы?

Если вы не хотите, чтобы бросить по какой-то причине, вы могли бы сделать

double d = num * 1.0 / denom;

Я не люблю кастинг примитивов, кто знает, что может случиться.

почему у вас есть иррациональный страх перед кастингом примитивов? Ничего плохого не случится, когда вы бросите int до double. Если вы просто не уверены в том, как это работает, посмотрите его в Спецификация Языка Java. Кастинг int to double это расширяющегося примитивного преобразования.

вы можете избавиться от дополнительной пары скобок путем литья знаменатель вместо числителя:

double d = num / (double) denom;

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

double d = 5 / (double) 20; //cast to double, to do floating point calculations

обратите внимание, что кастинг результат не буду

double d = (double)(5 / 20); //produces 0.0

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

1. double d = (double)5 / 20;
2. double v = (double)5 / (double) 20;
3. double v = 5 / (double) 20;

обратите внимание, что приведение результата не будет делать этого. Потому что первое деление выполняется в соответствии с правилом приоритета.

double d = (double)(5 / 20); //produces 0.0

Я не думаю, что есть какие-либо проблемы с кастинга как такового вы думаете об.

Тип Литья Является Единственным Способом


производства double от целочисленного деления - нет другого пути без литье (может быть вы не будете делать это явно, но это произойдет).

теперь есть несколько способов, которыми мы можем попытаться получить точный double значение (где num и denom are int типа, и конечно литье) -

  1. с явными кастинг:

    • double d = (double) num / denom;
    • double d = ((double) num) / denom;
    • double d = num / (double) denom;
    • double d = (double) num / (double) denom;

а не double d = (double) (num / denom);

  1. с неявным приведением:

    • double d = num * 1.0 / denom;
    • double d = num / 1d / denom;
    • double d = ( num + 0.0 ) / denom;
    • double d = num; d /= denom;

а не double d = num / denom * 1.0;
и не double d = 0.0 + ( num / denom );

использовать что-то вроде:

double step = 1d / 5;

(1d-это приведение к удвоению)

вы можете рассмотреть возможность обертывания операций. Например:

class Utils
{
    public static double divide(int num, int denom) {
        return ((double) num) / denom;
    }
}

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

просто использовать это.

int fxd=1;
double percent= (double)(fxd*40)/100;

лучший способ сделать это

int i = 3;
Double d = i * 1.0;

d is 3.0 now.