Single и Double – десятичные дроби
С типом дробных чисел Double мы встретились в 5.2.3. Познакомимся поближе с ним и с типом Single. Оба они предназначены для работы с целыми и дробными числами и различаются, согласно таблице, точностью и диапазоном значений.
Создайте кнопку и введите такую программу:
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim a, b, c As Single
a = 23.456
b = 100
c = a + b
WriteLine(a) : WriteLine(b) : WriteLine(c)
Dim d, f, g As Double
d = 123456789
f = 0.000555
g = d + f
WriteLine(d) : WriteLine(f) : WriteLine(g)
End Sub
Обратите внимание, что оператор Dim d, f, g As Double находится не на самом верху процедуры. Это ничего. Надо только, чтобы объявление переменной было расположено в процедуре раньше ее «употребления».
Запустите проект. Вот результат:
23,456
100
123,456
123456789
0,000555
123456789,000555
Все правильно. Попробуем теперь проверить тип Single на прочность, как мы проверяли тип Integer. Попробуем записать вместо a = 23.456 очень длинную дробь:
a = 23.45678901234567890123456789
Но VB не дает нам роскошествовать. Он прямо в окне кода укорачивает строку до:
a = 23.456789012345681
причем даже чуть-чуть искажает число. Поставим курсор мыши на этот литерал и увидим подсказку «Double». Почему? Ведь переменная a имеет тип Single! Дело в том, что VB, пока проект не запущен, не утруждает себя угадыванием смысла литералов в окне кода и все дробные литералы «стрижет под Double». Запустим проект. Вот первые три числа результатов:
23,45679
100
123,4568
Как видите, VB обрезал наши длинные числа до 7 значащих цифр. Сделал он это потому, что 4 байта, отведенные под ячейку памяти для переменной типа Single, не в состоянии вместить больше. Если мы хотим иметь большую точность, то объявляем наши переменные типом Double. Под переменную типа Double компьютер отводит в памяти 8 байтов и поэтому она может быть гораздо длиннее – 17 значащих цифр.
Попробуем задать очень маленькое число. Вместо f = 0.000555 напишем:
f = 0.0000000000000000000000000000000000000000000000000000000000000543
Но VB не любит в дробных числах большого числа нулей и вот, хоть запись и правильная и вполне по зубам типу Double, VB прямо в окне кода укорачивает строку до:
f = 5.43E-62
Это тоже правильная запись, а что она значит, объяснено чуть позже, в 5.4.7.
Поговорим о точности вычислений. Если вы до сих пор считаете, что компьютер все вычисления выполняет абсолютно точно, то ошибаетесь. Компьютер всего лишь очень точен. Очень, а не абсолютно. И в этом вы скоро убедитесь. Начнем хотя бы с того, что VB не умеет работать с обыкновенными дробями. Он не знает, что такое 1/3, поэтому нам приходится задавать компьютеру вместо числа 1/3 число 0,333333333333. Но это ведь не точная дробь 1/3, а только приблизительное значение. Чтобы она стала точным значением, число знаков после запятой должно быть бесконечным, а такое число не уместится в памяти компьютера. Следовательно, даже теоретически компьютер не может быть абсолютно точен.
Во-вторых, из-за ограниченности типа Double 17 значащими цифрами операции даже над очень точными числами выполняются не совсем точно. Что, например, напечатает такой фрагмент?:
Dim d, f, g As Double
d = 123456789
f = 0.00987654321098765
g = d + f
WriteLine(d) : WriteLine(f) : WriteLine(g)
Если вы думаете, что точную сумму 123456789,00987654321098765, то ошибаетесь, так как такое длинное число не уместится в типе Double. А напечатано будет вот что:
123456789
0,00987654321098765
123456789,009877
Десяток цифр из точного значения суммы обрезаны.
Целые литералы VB автоматически относит к типу Integer, а если они слишком длинные для Integer – к типу Long. Дробные литералы VB относит к типу Double. Все это он делает, не особенно обращая внимание на то, что переменные в том же операторе имеют другой тип.