Главная - Литература

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 [94] 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

Если значение целых чисел в вашей системе не превышает 2 147 483 647, промежуточный результат слишком велик для целого типа данных. В такой ситуации промежуточный результат, который должен быть равен / ООО ООО ООО ООО, на самом деле равен 727379968, поэтому, когда вы делите его на 100 ООО, вы получаете -77 вместо 100 000.

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

12.3. Числа с плавающей запятой

Главная особенность применения чисел с плавающей запятой в том, что многие дробные десятичные числа не могут быть точно представлены с помощью нулей и единиц, используемых в цифровом компьютере. В бесконечных десятичных дробях, таких как 1 /3 или 1 /7, обычно сохраняется только 7 или 15 цифр после запятой. В моей версии Microsoft Visual Basic 32-битное представление дроби 1/3 в виде числа с плавающей запятой равно 0,33333330. То есть точность ограничена 7 цифрами. Такая точность достаточна для большинства случаев, но все же способна иногда вводить в заблуждение.

Вот несколько рекомендаций по использованию чисел с плавающей запятой.

Ыщпт ттм Книги Избегайте сложения и вычитания слишком разных по

ШЩШт штщшы рш«- размеру чисел Для 32-битной переменной с плавающей Ш8шг1е«.0м.&пода- запятой сумма 1 000 000,00 + 0,1, вероятно, будет равна $т «ДйШ«шеяьные ресурс i оОО 000,00, так как в 32 битах недостаточно значимых ш* дш Ш, цифр, чтобы охватить интервал между 1 ООО ООО и 0,1. Ана-

логично 5 ООО 000,02 - 5 ООО 000,01, вероятно, равно 0,0.

Решение? Если вам нужно складывать настолько разные по величине числа, сначала отсортируйте их, а затем складывайте, начиная с самых маленьких значений. Аналогично, если вам надо сложить бесконечный ряд значений, начните с наименьшего члена, т. е. суммируйте члены в обратном порядке. Это не решит проблемы округления, но минимизирует их. Многие алгоритмические книги предлагают решения для таких случаев.

1 раш t для 0тшт Ыт- сравнений на равенство Числа с плавающей ших штШ 1 запятой, которые должны быть равны, на самом деле рав-

Атты всегда. Главная проблема в том, что два разных спо-

соба получить одно и то же число не всегда приводят к одинаковому результату. Так, если 10 раз сложить 0,1, то 1,0 получается только в редких случаях. Следующий пример содержит две переменных (nominal и sum), которые должны быть равны, но это не так.

Пример неправильного сравнения чисел с плавающей точкой (Java)

1- Переменная nominal - 64-битное вещественное число.

-double nominal =1.0; double sum = 0.0;



for ( int i = 0; i < 10; i++ ) {

- sum вычисляется как 10*0,1. Она должна быть равна 1,0.

sum += 0.1;

- Здесь неправильное сравнение.

-if ( nominal == sum ) {

System.out.println( "Numbers are the same." );

else {

System.out.println( "Numbers are different." );

Как вы, наверное, догадались, программа выводит:

Numbers are different.

Вывод каждого значения sum в цикле for выглядит так:

0.1 0.2

0.30000000000000004

0.7999999999999999 0.8999999999999999 0.9999999999999999

Таким образом, хорошей идеей будет найти альтернативу операции сравнения на равенство для чисел с плавающей запятой. Один эффективный подход состоит в том, чтобы определить приемлемый интервал точности, а затем использовать логические функции для выяснения, достаточно ли близки сравниваемые значения. Для этого обычно пишется функция EqualsQ, которая возвращает true, если значения попадают в этот интервал, и false - в противном случае. На языке Java такая функция может выглядеть так:

Пример метода для сравнения чисел с плавающей запятой (Java)

final double ACCEPTABLE DELTA = 0.00001; boolean Equals( double Termi, double Term2 ) {

if ( Math.abs( Termi - Term2 ) < ACCEPTABLE.DELTA ) {

return true; чения. Переменные здесь copp-

} жат цифры е именах. Пртшт

else { протиЁ шттьттт тфр в

return false; именах переменных т. е раз-

Перекистиа)! сшкка Этот пример дошатедшво того, что из кащого правила есть исклю-

mm 117.



Если код в примере «неправильного сравнения чисел с плавающей запятой» изменить так, чтобы для сравнения использовался этот метод, новое выражение получит следующий вид:

if ( Equals( Nominal, Sum ) ) ...

При запуске теста программа выведет сообщение:

Numbers are the same.

В зависимости от требований вашего приложения использование жестко закодированного значения ACCEPTABLE DELTA может быть недопустимо. Возможно, придется вычислять ACCEPTABLE DELTA на основании размера двух сравниваемых чисел.

Предупреждайте ошибки округления Проблемы с ошибками округления сходны с проблемами слишком разных по размеру чисел. У них одинаковые причины и похожие методики решения. Кроме того, далее перечислены способы решения проблем округления.

Измените тип переменной на тип с большей точностью. Если вы используете числа с одинарной точностью, замените их числами с двойной точностью и т. д.

Перекрутя боьша Как пра- * Используйте двоично-десятичные переменные (binary вило, конвертация в тип BCD coded decimal, BCD). BCD-числа обычно работают медлен-ттшьт гптт на проиаво- нее и требуют больше памяти для хранения, но предотвра-дйтельность. Если вы озабоне- щают множество ошибок округления. Это особенно важно, иы проблшой пщтттшь- j используемые переменные представляют собой долла-HOCTtf, см. раздал 25.6.

ры и центы или другие величины, которые должны точно

балансироваться.

Измените тип с плавающей запятой на целые значения. Это такая самодельная замена BCD-переменных. Возможно, вам придется использовать б4-битные целые, чтобы получить нужную точность. Этот способ предполагает, что вы сами будете отслеживать дробные части чисел. Допустим, изначально вы вели учет денежных сумм, применяя числа с плавающей запятой, при этом центы указывались как дробная часть. Это обычный способ обработки долларов и центов. Когда вы переключаетесь на целые числа, вам нужно вести учет центов с помощью целых, а долларов - с помощью чисел, кратных 100 центам. Иначе говоря, вы умножаете сумму в долларах на 100 и храните центы в этой переменной в интервале от О до 99. Такое решение может показаться абсурдным, но оно эффективно и с точки зрения скорости, и с точки зрения точности. Вы можете упростить эти манипуляции, создав класс DollarsAndCents, скрывающий целое представление чисел и предоставляющий необходимые числовые операции.

Проверяйте поддержку специальных типов данных в языке и дополнительных библиотеках Некоторые языки, включая Visual Basic, предоставляют такие типы данных, как Currency, предназначенные для данных, чувствительных к ошибкам округления. Если ваш язык содержит встроенный тип данных, предоставляющий такую функциональность, используйте его!



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 [94] 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294



0.0051