Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > oracle number -> BigDecimal


Автор: KostenkoSergey 11.9.2007, 11:06
Столкнулся с такой вот проблемой :
Выполняя запрос (select mynumber from mytable)в пл\скл девелопере получаю 9.8,
а при использовании 
Код

        ResultSet result  = stat.executeQuery(" select mynumber from mytable ");
        result.next();
        BigDecimal x = result.getBigDecimal("mynumber ");


Получаю 9.799999999999999

Подскажите с чем это связано и как побороть ?

Автор: dorogoyIV 11.9.2007, 11:20
если побороть в смысле округлить
Код

х.setScale(1, BigDecimal.ROUND_HALF_UP);

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

Автор: KostenkoSergey 11.9.2007, 11:44
Цитата(dorogoyIV @  11.9.2007,  11:20 Найти цитируемый пост)
если побороть 

да, я думал об этом - но в таком случае если в поле нумбер будет целое число - оно допишет .0, да и заранее сколько знаков после запятой будет я не знаю.

Автор: dorogoyIV 11.9.2007, 12:14
посмотри такой код. может пригодится?
Код

  BigDecimal x=new BigDecimal(12.3);
  BigDecimal y=new BigDecimal("12.3");

  System.out.println(x+"\n"+y);

Автор: KostenkoSergey 11.9.2007, 12:34
Цитата(dorogoyIV @  11.9.2007,  12:14 Найти цитируемый пост)
посмотри такой код. может пригодится?
 - не совсем понял, что ты хотел показать фрагментом кода.

Свой вопрос пока решил следующим образом: 
Код

...
        if (columType.equalsIgnoreCase("number")) {
          BigDecimal bd = _resultSet.getBigDecimal(i);
          if (bd != null)
            if (bd.scale() == 0) {
              // -- BD
              tmpElement.appendChild(doc.createTextNode(bd.toString()));
            } else {
              // -- Float
              tmpElement.appendChild(doc.createTextNode(Float.toString(bd.floatValue())));
            }
        }
...


ps буду надеяться размерности флоата будет достаточно.

Автор: dorogoyIV 11.9.2007, 13:56
Цитата(KostenkoSergey @  11.9.2007,  12:34 Найти цитируемый пост)
 - не совсем понял,

в учебнике у меня написано:
Цитата

В классе BigDecimal четыре конструктора: 

1.BigDecimal (Biglnteger bi) — объект будет хранить большое целое bi, порядок равен нулю; 
2.BigDecimal (Biglnteger mantissa, int scale) — задается мантиса mantissa и неотрицательный порядок    scale объекта; если порядок scale отрицателен, возникает исключительная ситуация; 
3.BigDecimal (double d) — объект будет содержать вещественное число удвоенной точности d ; если значение d бесконечно или NaN , то возникает исключительная ситуация; 
4.BigDecimal (String val) — число задается строкой символов val , которая должна содержать запись числа по правилам языка Java. 
При использовании третьего из перечисленных конструкторов возникает неприятная особенность, отмеченная в документации. Поскольку вещественное число при переводе в двоичную форму представляется, как правило, бесконечной двоичной дробью, то при создании объекта, например, BigDecimal(0.1) , мантисса, хранящаяся в объекте, окажется очень большой. Но при создании такого же объекта четвертым конструктором, BigDecimal ("0.1") , мантисса будет равна просто 1. 


Автор: niasilil 13.11.2008, 08:09
bump

Правлю чужой код, сравниваю баланс - фиг вам, куда то подевался цент. 
Пытаюсь найти, все вроде нормально, но цента нет. Было что то типа 89.21 стало несколько платежей но в сумме 89.20
Оказалось оно - кто то использовал BigDecimal(double) вместо BigDecimal(String). 

Вообще непонятен глубокий смыслтакого поведения конструктора с double. Ведь ясно же что баг, так нет, записали в API как feature. 

Автор: w1nd 13.11.2008, 10:02
Цитата(niasilil @  13.11.2008,  08:09 Найти цитируемый пост)
Вообще непонятен глубокий смыслтакого поведения конструктора с double. Ведь ясно же что баг, так нет, записали в API как feature. 

Это не баг, это свойство double. Машинные числа с плавающей точкой нельзя использовать для точных расчётов в принципе.

Автор: niasilil 16.11.2008, 08:19
Баг это, баг. Просто его объявили фичей. 
Ничего мы тут не считаем, просто создаем объект. Можно просто в лоб заменить весь конструктор 

Код

public BigDecimal(double val) {
    ....
}


на 
Код

public BigDecimal(double val) {
    this(new Double(val).toString());
}


и все будет работать как и должно. Мне Рабинович напел что в сях такого безобразия нет, сам не проверял. 
Вот
Код

    public static void main(String[] args) {
        BigDecimal bd1 = new BigDecimal(0.1);
        BigDecimal bd2 = new BigDecimal(new Double(0.1).toString());
        System.out.println(bd1 + "\n" + bd2);
    }

выдает как и положено 
0.1000000000000000055511151231257827021181583404541015625
0.1

Автор: dorogoyIV 16.11.2008, 12:04
Цитата(niasilil @  16.11.2008,  08:19 Найти цитируемый пост)
Баг это, баг

не баг это, не баг!
повторите первый курс института (высшая математика)  smile 

Автор: niasilil 17.11.2008, 03:38
Цитата(dorogoyIV @ 16.11.2008,  12:04)
Цитата(niasilil @  16.11.2008,  08:19 Найти цитируемый пост)
Баг это, баг

не баг это, не баг!
повторите первый курс института (высшая математика)  smile

и как же это не баг если два конструктора выдают два разных значения? просто из общих соображений. 
Код

double d = 0.1;
BigDecimal bd1 = new BigDecimal(d);
BigDecimal bd2 = new BigDecimal(d + "");

dorogoyIV, какую конкретно часть первого курса высшей математики вы имеете ввиду? я как бы немного с этим знаком, кандидат физмат наук как никак. Было бы все же полезнее аргументировать, а не так. Я не обязан вам верить на слово. 

фиг с ним, баг это или не баг. Но вот объясните мне зачем используется два разных способа создания объекта в двух разных конструкторах? Какой в этом смысл? По мне так это бред полный. 

Автор: dorogoyIV 17.11.2008, 12:30
niasilil
Цитата(dorogoyIV @  11.9.2007,  13:56 Найти цитируемый пост)
при переводе в двоичную форму

наверное с этим связано?

Автор: w1nd 17.11.2008, 13:23
Цитата(niasilil @  17.11.2008,  03:38 Найти цитируемый пост)
и как же это не баг если два конструктора выдают два разных значения?

Не разные способы конструкции приводят к отклонениям, а разные значения параметров. Иными словами, 0.1D - совсем не то же самое, что "0.1". Именно об этом и просил вас вспомнить dorogoyIV.

Автор: avvo 21.11.2008, 00:48
http://en.wikipedia.org/wiki/IEEE_754-1985

А высшая математика тут, да, не при чем. Тут только "низшая", то бишь арифметика. smile

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

Автор: niasilil 21.11.2008, 07:29
Хотел поспорить, аргументы подготовил, но все стер нафиг - разговор немого с глухим получается. 
Вы мне объясняете почему теряется точность, так это очевидно почему. И из кода конструкторов видно. Мне совсем неочевидно другое. 
Как по вашему, где может применяться конструктор new BigDecimal(double d), если сразу в API написано что результат непредсказуем? Пример бы помог меня убедить. 
Если примеров нет, то предлагаю согласиться что разумно было бы depricate этот конструктор и все тут. 

Автор: w1nd 21.11.2008, 11:58
Цитата(niasilil @  21.11.2008,  07:29 Найти цитируемый пост)
Как по вашему, где может применяться конструктор new BigDecimal(double d), если сразу в API написано что результат непредсказуем? Пример бы помог меня убедить. 

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

И ещё раз. Ваше упование на точность при использовании double - странно. Такие числа нельзя даже сравнивать с помощью оператора ==.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)