-3

I need to solve the issue related to the double representation. For example, I have the following set of values:

id: 1 val: 8.11               floor: 8.109999  ceil: 8.11
id: 2 val: 8.31               floor: 8.31      ceil: 8.310001
id: 3 val: 8.27               floor: 8.27      ceil: 8.27
id: 4 val: 12.469999999999999 floor: 12.469999 ceil: 12.47
id: 5 val: 1.9700000000000002 floor: 1.97      ceil: 1.970001

where

val = value coming from a certain operation,
value_ceil = Math.ceil(value * 1000000)/1000000;
value_floor = Math.floor(value * 1000000)/1000000;

As you can see, there are different "scenarios" which fit my needs:

* when the initial value is "ready" (= as expected):
    - all of them give me the desired output (id 3)
    - val and floor give me the desired output (id 2)
    - val and ceil give me the desired output (id 1)
* when the initial value has to be "adjusted":
    - floor provides the desired output (id 5)
    - ceil provides the desired output (id 4 )

Is there a unique way to manage all the cases obtaining the desired double value?

Thanks

EDIT: Could

Math.round(value * 1000000.0)/1000000.0

solve the issue?

Fab
  • 1,145
  • 7
  • 20
  • 40
  • Related: http://stackoverflow.com/questions/588004/is-floating-point-math-broken – OH GOD SPIDERS Mar 09 '17 at 16:51
  • Why do you care about the this rounding? Is it for pretty printing the output? Or does your program rely on it for correctness in someway? If it's the first, you should look into using `String.format()` to control how output is printed. In the second case you're going to have problems because of the inherent nature of floating point number precision, and you should consider either doing comparisons with an epsilon term or using `BigDecimal`. If you're representing money you should never use float/double. – whaleberg Mar 09 '17 at 17:06
  • @whaleberg It is the second case. I'm not representing money, but weather indicators. I used double in order to manage all the data types available in a Oracle DBMS, which has your own data types. In addition, I used Apache Commons Math, which doesn't rely on BigDecimal, so I have to adjust its output in order to treat each value in the correct and proper way. – Fab Mar 09 '17 at 17:12
  • @whaleberg It seems the round function works fine. Any comment about that? – Fab Mar 09 '17 at 17:13
  • 1
    Pretty similar to [How to round a number to n decimal places in Java](http://stackoverflow.com/questions/153724/how-to-round-a-number-to-n-decimal-places-in-java) – Salem Mar 09 '17 at 17:26
  • I would be careful when using that rounding method. I suspect there are inputs that will fail, for example if your inputs are very large they may overflow and cause incorrect results. It may work if you have a very restricted range of potential inputs, but I suspect there are small numbers that will fail as well. See the discussion in the question that 1bluestone linked to. If you do comparisons with floating point numbers it's usually a good idea to use an epsilon value in case there are precision issues. – whaleberg Mar 09 '17 at 17:44

1 Answers1

0

You are putting a division after java made the approximation...

Do this:

value_ceil = Math.ceil((value * 1000000)/1000000);
value_floor = Math.floor((value * 1000000)/1000000);

Or if you want for example this:

val: 12.190000000000001 floor: 12.19 ceil: 12.2

Then this should work:

double val = 12.190000000000001;
double value_ceil  = Math.floor(val*100)/100;
double value_floor = Math.ceil(val*100)/100;
Dazak
  • 1,011
  • 2
  • 9
  • 17
  • Note that now the whole expression is inside parentheses before call the functions – Dazak Mar 09 '17 at 16:53
  • val: 12.190000000000001 floor: 12.0 ceil: 13.0. This is not what I expect – Fab Mar 09 '17 at 16:59
  • 1
    then what do you expect? floor=12.19 and ceil = 12.2? – Dazak Mar 09 '17 at 17:12
  • In this case, 12.19. See examples in the question for other cases. – Fab Mar 09 '17 at 17:14
  • As stated in the question, Math.floor works fine in some cases, Math.ceil in other ones. I need a common way. Is Math.round a possible solution? – Fab Mar 09 '17 at 17:16
  • 2
    @Fab `floor` and `ceil` are defined _mathematically_ [to round to the nearest whole number that is less or greater respectively](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions). You can't really get `floor` to do anything different. [This question](http://stackoverflow.com/questions/153724/how-to-round-a-number-to-n-decimal-places-in-java) might help. – Salem Mar 09 '17 at 17:25