0

I have this strange issue of having to cap the precision of double numbers to a number of decimal places, or no decimal places at all, where the precision is handed to me like so: 0.001, 0.1, 1, 0.00001, etc.

So I could be given, for example, 1.234247324 and a precision indicator of 0.001, and with that I would need to return 1.234. If Instead I had been handed a precision of 1.0, I would then return 1 (no decimal places), and so forth.

I'm not sure how to go about this. Does anyone has pointers on how to tackle this?

Thank you!

Edy Bourne
  • 5,679
  • 13
  • 53
  • 101
  • 4
    Consider the BigDecimal. Also consider the slew of similar questions comming your way. – matt Jan 08 '18 at 19:01
  • 1
    For example: https://stackoverflow.com/questions/153724/how-to-round-a-number-to-n-decimal-places-in-java?rq=1 – matt Jan 08 '18 at 19:01
  • Note that most such values, including your example of 1.234, are not precisely representable as an IEEE 754 floating point value. – TypeIA Jan 08 '18 at 19:02
  • I really like the accepted answer in this question. https://stackoverflow.com/questions/26120311/why-does-adding-0-1-multiple-times-remain-lossless?rq=1 It shows how to use a BigDecimal, and it shows the difference between a BigDecimal and a double, *and* the printed out versions. Definite read. – matt Jan 08 '18 at 19:04
  • @matt I did not find anything like this, really. The question you pointed givens the precision as a number of decimal places, like 5, 10, etc, which is different. If anyone can help me convert 0.0001 to 4, for example, then I can take it from there. :) – Edy Bourne Jan 08 '18 at 19:04
  • 1
    @EdyBourne you have to use big decimal. The "double" doesn't store values like that. https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html – matt Jan 08 '18 at 19:06
  • @EdyBourne About obtaining the number of decimal places from a precision indicator, note that (number of decimals) = log10(1/precision). E.g. log10(1/0.0001) = 4. – Robert Dodier Jan 08 '18 at 19:09
  • It really depends on how accurate you have to be. double does not store *decimal* digits, so when you're asking for decimal digits, it is tricky. That is why you use a BigDecimal, the hint is in the name Decimal, which refers to the 10. Maybe zhh's answer suits you, but your value is not actually what you always see. Sometimes it has tiny values at the very end. – matt Jan 08 '18 at 19:18

3 Answers3

1

Start with your value, and create a BigDecimal, then round to what you want.

double value = 1.23456; //not actually equal to that, but pretend.
BigDecimal better = new BigDecimal(value);
BigDecimal rounded = better.round(new MathContext(3));

Rounded is now the actual value you want. What can you do with the precision indicator?

BigDecimal precision = new BigDecimal("0.001");

Now you can get the scale of the precision, which you can use for rounding.

System.out.println(precision.scale());
//outputs 3.

That would be similar to using the logarithm.

matt
  • 10,892
  • 3
  • 22
  • 34
  • I see, thanks for updating the answer too, it helped me understand why this is a better way to go. o/ – Edy Bourne Jan 08 '18 at 19:22
  • @EdyBourne glad it help, it is a bit tough to know your requirements. So if it turns out this isn't quite what you need, go back and edit your question so it doesn't look like the classic floating point precision problem. – matt Jan 08 '18 at 19:29
0

Use a hybrid approach of the two other answers allows unusual precisions like 0.25 to be specified:

BigDecimal rounded = (x / precision).round(new MathContext(0)) * precision;
Eric
  • 95,302
  • 53
  • 242
  • 374
-1

Try this code

double x = 1.234247324;
double p = 0.001;
double y = (int)(x * 1 / p) / (1 / p);

Don't really understand what you want to do but this results 1.234.

zhh
  • 2,346
  • 1
  • 11
  • 22
  • 1
    @EdyBourne it is not correct. `double` is not stored like that. Ill paste you a big decimal example. – matt Jan 08 '18 at 19:08
  • @Edy Bourne If you want high-precision then use ```BigDecimal``` else just use a simple floating arithmetic. – zhh Jan 08 '18 at 19:17
  • This is correct in that it rounds `x` to nearest multiple of `(double) 0.001`. Of course, `(double) 0.001` is not exactly 1/1000. – Eric Jan 08 '18 at 20:30