Опубликован: 27.09.2006 | Уровень: для всех | Доступ: свободно | ВУЗ: Московский государственный индустриальный университет
Лекция 4:

Особенности представления чисел в ЭВМ

< Лекция 3 || Лекция 4: 123 || Лекция 5 >

Вещественные числа

Обсуждаемые в данной секции вопросы значительно более полно рассмотрены в четвертой главе классической книги Кнута [7].

Для представления вещественных чисел в языке Java используют переменные и константы типов float и double. Величины первого из них занимают четыре байта, а второго — восемь.

В отличие от множества целых чисел \mathbb{Z} вещественные числа \mathbb{R} обладают свойством полноты: между любыми двумя различными числами всегда найдется отличное от них третье. Понятно, что любой из способов представления бесконечного множества вещественных чисел с помощью некоторого конечного множества \mathbb{R}_M не даст возможности сохранить свойство полноты. Наиболее распространенным способом реализации вещественных чисел на ЭВМ является использование чисел с плавающей точкой. При этом множество \mathbb{R}_M оказывается состоящим из элементов вида

f = \pm (\frac{\alpha_1}{p}+\frac{\alpha_2}{p^2}+\ldots+
\frac{\alpha_n}{p^n})p^e,

где целые числа \alpha_i для всех i из диапазона от 1 до n удовлетворяют соотношению 0 \leqslant \alpha_i \leqslant p - 1, а величина e лежит в диапазоне от L до U ( L \leqslant e \leqslant
U ). Число p является при этом основанием системы счисления (чаще всего это 2), константа n задает точность представления чисел (для типа double она больше, чем для float ), а диапазон [L,U] определяет область значений экспоненты (для типа double он также больше, чем для float ).

Число \pm (\frac{\alpha_1}{p}+\frac{\alpha_2}{p^2}+\ldots+
\frac{\alpha_n}{p^n}) принято называть мантиссой числа f с плавающей точкой. Часто требуют, чтобы для всех чисел f \ne 0 величина \alpha_1 была ненулевой. Такие числа с плавающей точкой называют нормализованными.

В языке Java для кодирования величин типов float и double также используют числа с плавающей точкой. При этом часть из имеющегося множества бит используют для размещения экспоненты e, а остальные биты — для размещения мантиссы.

Для того чтобы хорошо понять, что же представляет из себя множество \mathbb{R}_M нормализованных чисел с плавающей точкой, полезно изобразить его на числовой прямой для случая небольших n, L и U. Подобная задача приведена в конце параграфа. Сейчас же нам будет достаточно весьма качественного описания этого множества.

Так как \mathbb{R}_M симметрично относительно начала координат, то можно разобраться только с неотрицательными числами. Нуль, конечно же, принадлежит искомому множеству. Ближайшая к нулю следующая точка получается при \alpha_1 = 1, \alpha_2 = \alpha_3 = \ldots = \alpha_n = 0 и e=L. Это число для чисел типов float и double определено, как MIN_VALUE в классах java.lang.Float и java.lang.Double соответственно.

Правее располагается множество точек, следующих друг за другом с шагом 2^{L-n}. Затем шаг увеличивается. Потом еще. И еще. При e=U расстояние между двумя соседними точками множества \mathbb{R}_M достигает 2^{U-n}. Самая правая точка множества получается при \alpha_1 = \alpha_2 = \ldots = \alpha_n =
1 и e=U. Для типов float и double это число определено, как MAX_VALUE в классах java.lang.Float и java.lang.Double.

Кроме перечисленных (и симметричных им отрицательных) значений в результате выполнения некоторых операций могут получиться также следующие особые значения: плюс бесконечность ( POSITIVE\_INFINITY ), минус бесконечность ( NEGATIVE\_INFINITY ), минус ноль и не число ( NaN ). Например, при делении единицы на минус ноль получается минус бесконечность.

Описанные особенности множества машинных вещественных чисел \mathbb{R}_M приводят к тому, что не для всех его элементов верны следующие соотношения, всегда справедливые для множества настоящих вещественных чисел \mathbb{R}:

  • x+1>x ;
  • x+x существует;
  • (x\cdot 2) / 2 = x ;
  • (x /2) \cdot 2 = x ;
  • a+(b+c) = (a+b) + c ;
  • a+b+c = c+b+a.

Приведем несколько примеров, иллюстрирующих эти особенности множества \mathbb{R}_M.

Задача 4.1. Предъявите действительное (типа double ) число x такое, что x + 1 = x, а (x\cdot 2) / 2 \ne x. Воспользуйтесь тем, что класс java.lang.Double определяет константу MAX_VALUE.

Текст программы

public class DblMaxVal {
    public static void main(String[] args) {    
        double x = Double.MAX_VALUE;
        double y = x + 1.0;

        if (x == y) {
            Xterm.print("Для числа ");
            Xterm.print("x = " + x, Xterm.Blue);
            Xterm.print(" величины x и (x+1) ");
            Xterm.print("равны!\n", Xterm.Red);
        }
	
        y = 2.0 * x;
        double z = y / 2.0;

        if (x != z) {
            Xterm.print("Для числа ");
            Xterm.print("x = " + x, Xterm.Blue);
            Xterm.print(" величины x и (2.0*x)/2.0 ");
            Xterm.print("различны\n", Xterm.Red);
            Xterm.print("и равны соответственно");
            Xterm.print(" " + x, Xterm.Red);
            Xterm.print(" и");
            Xterm.print(" " + z + "\n", Xterm.Red);
        }
    }
}

Задача 4.2.Предъявите такие действительные (типа double ) числа a, b и c такие, что a+(b+c) \ne (a+b)+c.

Достаточно вспомнить, что точки множества \mathbb{R}_M расположены на числовой прямой неравномерно.

Текст программы

public class DblNoAssociative {
    public static void main(String[] args) {    
        double x = 1.0e-16;
	
        double y =  1.  + (x  +  x);
        double z = (1.  +  x) +  x ;

        if (y != z) {
            Xterm.print("Для числа ");
            Xterm.print("x = " + x, Xterm.Blue);
            Xterm.print(" величины 1.+(x+x) и (1.+x)+x ");
            Xterm.print("различны\n", Xterm.Red);
            Xterm.print("и равны соответственно");
            Xterm.print(" " + y, Xterm.Red);
            Xterm.print(" и");
            Xterm.print(" " + z + "\n", Xterm.Red);
        }
    }
}

Иногда даже работа с казалось бы не слишком маленькими или огромными по абсолютной величине числами может привести к удивительным результатам. Рассмотрим задачу о решении квадратного уравнения.

Задача Напишите программу, вводящую действительные коэффициенты a, b и c квадратного уравнения a x^2 + b x + c = 0 с положительным дискриминантом, находящую оба корня этого уравнения.

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

Текст программы

public class SquareEquation {
    public static void main(String[] args) throws Exception {    
        double a = Xterm.inputDouble("Введите число a -> ");
        double b = Xterm.inputDouble("Введите число b -> ");
        double c = Xterm.inputDouble("Введите число c -> ");

        if (a == 0.) {
            Xterm.println("Уравнение не квадратное", Xterm.Red);
            System.exit(0);
        }

        if (b*b - 4.*a*c <= 0.) {
            Xterm.println("Дискриминант неположителен", Xterm.Red);
            return;
        }

        double x1 = ( -b - Math.sqrt(b*b - 4.*a*c) ) / (2.*a);
        double x2 = ( -b + Math.sqrt(b*b - 4.*a*c) ) / (2.*a);

        Xterm.println("Корни уравнения:");
        Xterm.println("x1 = " + x1, Xterm.Blue);
        Xterm.println("x2 = " + x2, Xterm.Blue);
    }
}

Для извлечения квадратного корня здесь используется метод sqrt класса Math. Вызов метода System.exit и применение оператора return, которые в теле метода main почти эквивалентны и приводят к немедленному завершению выполнения программы, позволяет обойтись без ветви else оператора if-else. Остальная часть программы комментариев не требует.

Попробуйте, однако, выполнить эту программу при a=0.2E-16 и b=c=1.0 — первый корень уравнения x1 окажется равным -5.0E16, а второй x2 — нулю.

Если подставить эти значения в выражение a x^2 + b x + c, то и для x1 и для x2 его значение окажется равным единице, а не нулю. Подобная ошибка для первого, весьма большого по величине корня, представляется вполне естественной, но вот соглашаться с тем, что нуль является корнем данного уравнения, совсем не хочется. Этой проблеме посвящена одна из приведенных ниже задач.

< Лекция 3 || Лекция 4: 123 || Лекция 5 >
Анастасия Халудорова
Анастасия Халудорова
екатерина яковлева
екатерина яковлева