Оператор модуля Java

Почему этот код печатает 2.4099999999999997, а не только 2.41

public class Main
{
    public static void main(String args[])
    {
        double d = 5.55%3.14;
        System.out.println(d);
    }
}

person AbhinavChoudhury    schedule 22.02.2013    source источник
comment
почему вы все это голосуете против, вам нужно глубокое понимание арифметики с плавающей запятой, чтобы понять это ..   -  person cIph3r    schedule 22.02.2013
comment
Нет ничего очень глубокого в том, что float / double представляет действительные числа в нескольких байтах, и для этого им нужно делать приближения ... Это базовая информатика.   -  person Cyrille Ka    schedule 22.02.2013
comment
@CyrilleKarmann, хорошо ... зная, что это очень легко, понять это гораздо сложнее ... но все же трудно полностью понять статью, которую опубликовал Пшемо ...   -  person cIph3r    schedule 22.02.2013
comment
Я согласен с тем, что связанная статья довольно сложна для новичка.   -  person Cyrille Ka    schedule 22.02.2013
comment
Проблема в том, что ваш инструктор CompSci 101 не смог на второй или третий день занятий объяснить представление чисел (а не только с плавающей запятой) и их последствия. (Или, может быть, вы проспали этот урок?)   -  person Hot Licks    schedule 22.02.2013
comment
(Следует отметить, что 3,14 - плохое приближение числа Пи.)   -  person Hot Licks    schedule 22.02.2013
comment
@ cIph3r Не волнуйтесь, если вы не поняли статью. Это одна из тех вещей, которые часто связывают, но редко читают.   -  person phant0m    schedule 04.03.2013


Ответы (4)


Проблема не в операторе по модулю, а в природе чисел с плавающей запятой. Двойник не может содержать точное значение 5,55, 3,14 или 2,41, поэтому вы получите приблизительный ответ.

Чтобы лучше понять это, попробуйте записать значение 1/3 в виде десятичной дроби, когда у вас есть ограниченное пространство на бумаге для его записи. В итоге вы получите что-то вроде 0.33333, что является приблизительным значением фактического значения. То же самое происходит с 5.55, когда вы записываете его в двоичном формате - он превращается в 101.10001100110011001100110011..., который где-то обрезается, чтобы соответствовать пространству двойника.

person Medo42    schedule 22.02.2013

import java.text.DecimalFormat;

double d = 5.55%3.14;       
DecimalFormat df = new DecimalFormat("#.##");
System.out.println( df.format( d ));

Добавить DecimalFormat

Редактировать:

Вы также можете

    double d = 5.55%3.14;
    System.out.printf("%1$.2f", d);
person ThePr0gr4mm3r    schedule 22.02.2013
comment
ну, на самом деле это не решает проблему, десятичный форматер просто округляет неточность ... DecimalFormat df = new DecimalFormat("##.###################"); покажет вам .. - person cIph3r; 22.02.2013
comment
Честно говоря, во многих случаях это вполне приемлемое решение. - person Medo42; 22.02.2013

Java double может иметь проблемы с точностью.

Почему бы тебе не попробовать BigDecimal?

person vikingsteve    schedule 22.02.2013
comment
Из-за проблем с точностью это звучит как ошибка; это не проблема, это плавающая точка. - person LittleBobbyTables - Au Revoir; 22.02.2013
comment
И BigDecimal этого не решает: import java.math.BigDecimal; public class Main { public static void main(String[] args) { final BigDecimal d = new BigDecimal(5.55); final BigDecimal APPROXPI = new BigDecimal(3.14); System.out.println(d.remainder(APPROXPI)); //2.409999999999999698019337301957421004772186279296875 } } - person cIph3r; 22.02.2013
comment
@ cIph3r на самом деле BigDecimal решает эту проблему, но нам нужно использовать строковое представление чисел в аргументах конструктора, таких как BigDecimal("5.55") и BigDecimal("3.14"), чтобы получить точные значения. Ознакомьтесь с этим объяснением. - person Pshemo; 23.02.2013
comment
@Pshemo хорошо, это работает: import java.math.BigDecimal; public class Main { public static void main(String[] args) { final BigDecimal d = new BigDecimal("5.55"); final BigDecimal APPROXPI = new BigDecimal("3.14"); System.out.println(d.remainder(APPROXPI)); } } И это абсолютно логично - person cIph3r; 23.02.2013

причина в том, что java не выполняет математику так, как мы. java использует двоичные числа (из главы 4 большой книги Хорстманна по java), поэтому для компьютера 435 = 4 * 10 ^ 2 + 3 * 10 ^ 1 + 5 * 10 ^ 0

это происходит потому, что двоичными числами (1 или 0) легче манипулировать, поскольку переключатели в компьютере либо включены, либо выключены (1 или 0).

это приводит к случайным проблемам с округлением. если вы хотите заставить его округляться, тогда используйте десятичный формат, или если вам просто нужно округленное отображаемое значение, вы можете использовать String.format или printf

person Jeff Hawthorne    schedule 22.02.2013