Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Странная потеря точности 
:(
    Опции темы
danilsl
Дата 22.5.2006, 17:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 78
Регистрация: 15.3.2006

Репутация: нет
Всего: нет



Вот примитивнейшая прога

Код

package test;

public class Main {
  
  public static void main(String[] args) {
    for (double i = 1.001; i < 1.002; i += .0001){
      System.out.println(i);
    }
  }
  
} //NetBeans IDE 5.0



и вот её результаты
Цитата

1.001
1.0010999999999999
1.0011999999999999
1.0012999999999999
1.0013999999999998
1.0014999999999998
1.0015999999999998
1.0016999999999998
1.0017999999999998
1.0018999999999998
1.0019999999999998



Если запускать не в IDE, результаты теже.
Откуда растёт эта потеря точности, ведь все числа с запасом влезают в разрядную сетку типа double 
PM MAIL   Вверх
COVD
Дата 22.5.2006, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Не влезают. 1.0011 как вы видите не влезает. Точное представление десятичного числа в двоичной форме не всегда влезает. Тут уже приводили пример, как например простая дробь 1/3  дает бесконечную дробь в десятичной форме 0.3(3). Аналогично при переходе из десятичной формы в двоичную.   
PM MAIL   Вверх
ALKS
Дата 22.5.2006, 17:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 354
Регистрация: 22.3.2006

Репутация: 1
Всего: 11



и сие справедливо для любых языков програмирования работающих с "реальными" простыми типами. так что не в Java дело smile 
PM   Вверх
YuG
Дата 22.5.2006, 17:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 160
Регистрация: 20.2.2006

Репутация: нет
Всего: 4



danilsl, думаю, это происходит из-за приведения типов.
Как побороть для FOR не понял.

Вот так работает :)
Код

        double i = 1.0011D;
        while (i < 1.002D) {
            i += 0.0001D;
            System.out.println(i);
        }

PM WWW ICQ Skype   Вверх
Bulat
Дата 22.5.2006, 17:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


татарский Нео
***


Профиль
Группа: Завсегдатай
Сообщений: 1701
Регистрация: 22.3.2006
Где: Альметьевск

Репутация: 4
Всего: 57



Да, да, да сам пару дней назад столкнулся с подобной проблемой.
Единственный выход который мне посоветовали округлять 


--------------------
менеджер по кодеврайтингу  smile 
PM MAIL WWW   Вверх
carper
Дата 23.5.2006, 14:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 1
Всего: 8



Bulat
Можно так:

Код

  public static void main(String[] args)  {
    for (int i = 10010; i < 10020; i += 1) {
      System.out.println((double)i/10000);
    }
  }

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

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

Например, не судите за качество - писал, что в голову с ходу пришло:

Код

import  java.math.*;
public class test {
  
  public static void main(String[] args)  {
    BigDecimal i1= new BigDecimal(1.0010);
    i1=i1.setScale(4, RoundingMode.DOWN);
     
    BigDecimal delta= new BigDecimal(.0001);
    delta= delta.setScale(5,RoundingMode.DOWN); 
   
    BigDecimal i2= new BigDecimal(.0001);
    i2= i2.setScale(5,RoundingMode.DOWN); 

    for (int i=0; i<10; i++) {
      System.out.println(i1.add(i2));
      i2=i2.add(delta);
    }//for
  }
  
} 

 
PM MAIL   Вверх
chief39
Дата 23.5.2006, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 15
Всего: 77



Цитата(carper @  23.5.2006,  14:40 Найти цитируемый пост)
Плюс стараться избегать операций с десятичными числами без реальной необходимости, хотя бы исходя из того, что, как тут уже говорилось, нормальная математика полагает, что 1/3+1/3+1/3 - это строго 1, а не нечто с периодами после запятой.


десятичное счисление - точно такая же математика, как и двоичное.
И у ЛЮБОЙ системы счисления есть "слабые места".
В этом плане десятичная ничуть не слабее двоичной/троичной/восьмиричной
Другое дело, что в памяти сохраняется как двоичное....

Но. Большинство чисел в бизнес-уровне хотят и должны корректно оперировать десятичными(!) числами.

Система, в разработке которой сейчас учавствую, все числовые значения из уровня бизнес-логики содержит в BigDecimal. Хотя он и громоздкий. 


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
carper
Дата 23.5.2006, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 1
Всего: 8



chief39, 
Цитата
Большинство чисел в бизнес-уровне хотят и должны корректно оперировать десятичными(!) числами


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

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

Тот же BigDecimal не просто громоздкий, он еще очень медленный и порождает кучу объектов, т.е. казалось бы в тех областях, где больше всего желательны десятичные числа, сам BigDecimal вовсе не так уж желателен из-за вышеперечисленных недостатков.


Цитата

И у ЛЮБОЙ системы счисления есть "слабые места".

Я бы сказал, что тут слабое место не в системе счисления, а в представлении чисел в компьютере.
Просто надо с этим смириться. smile
 
PM MAIL   Вверх
chief39
Дата 23.5.2006, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 15
Всего: 77



Цитата(carper @  23.5.2006,  17:11 Найти цитируемый пост)
Я просто посоветовал уходить от десятичных дробей там, где это возможно - думаю довольно безобидный совет при правильном применении.

Это да smile Но в денежных(а такое почти в каждой системе) вычислениях лучше всё-таки не уходить :-/

Цитата(carper @  23.5.2006,  17:11 Найти цитируемый пост)
(а это чертовски неприятная задача отслеживать места накопления ошибки)

Вот-вот! Ещё куда ни шло копаться вечерком спокойно и дебажить прогу, но совсем другое - когда система, работающая с деньгами, начинает их где-то(!) терять.
Причём найти это место, допустим, ещё не так страшно... А вот исправить неверные результаты сложных риалтайм расчётов на лету - это повешению подобно smile

Цитата(carper @  23.5.2006,  17:11 Найти цитируемый пост)
Я бы сказал, что тут слабое место не в системе счисления, а в представлении чисел в компьютере.
Просто надо с этим смириться. 

Я вот иногда думаю.... Почему люди считали по 10 пальцам а не по двум рукам? smile))
Сколько проблем решилось бы...
И почему в джаве нет просто Decimal... smile
 


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
Bulat
Дата 24.5.2006, 08:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


татарский Нео
***


Профиль
Группа: Завсегдатай
Сообщений: 1701
Регистрация: 22.3.2006
Где: Альметьевск

Репутация: 4
Всего: 57



2carper 
В своем случае-то я разобрался, да и в принципе ты советуешь почти тоже, но лично в моем случае я сначала умножал на 1000, а потом округлял переводя в тип int из double, а потом снова делил на 1000 и снова в double. А про BigDecimal не юзал, но мне сказали пару серьезных причин почему не стоит его применять, если нет существенной необходимости 


--------------------
менеджер по кодеврайтингу  smile 
PM MAIL WWW   Вверх
Metal_Heart
Дата 24.5.2006, 08:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а почему бы и нет?
**


Профиль
Группа: Участник
Сообщений: 728
Регистрация: 31.3.2005
Где: Москва

Репутация: 4
Всего: 12



раз уж пошла такая пляска smile 
вот нашёл небольшое описание:
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=374 

Это сообщение отредактировал(а) Metal_Heart - 24.5.2006, 08:42


--------------------
 не стыдно учиться, а стыдно не учиться 
PM ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0537 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.