2

Is there a way using Java's standard libraries to format a number to the format of another number?

Say that I have a number double a = 3.03

Can I use the number a as a model for formatting so that a number double b = 56.0934143 formats to the String "56.09" by doing something like this formatNumber(b, a)

Joakim
  • 3,224
  • 3
  • 29
  • 53

4 Answers4

3

What you're asking is possible in some sense but can get tricky...

The challenge stems from how floating point numbers are represented. See this discussion. Looking at a floating point number, it's difficult to determine with certainty the number of digits in base 10 the user would want.

For example, if you represent 3.03 with a single precision floating point number and convert back to base 10, you get something closer to 3.029999971389771. This is because 3.03 cannot be perfectly represented in base 2.

So you will need some complicated logic to figure out that if a float is 3.029999971389771 the user probably wants a two decimal place number 3.03. It's doable in some sense. If no additional error is added, Java libraries can do it. Excel does it, but it's a trickier problem than you think.


You might be able to get something that mostly works with some of the other answers that use BigDecimal. If the number you refer to as a is a hard coded constant, it may work fine, but if not, it's very likely you'll occasionally end up with far more digits than you intend.

Example 1 of big decimal approach going wrong

double x1 = 3.1;   
double x2 = Math.acos(Math.cos(x1));   //take the cosine and then inverse
                                       //to introduce a TINY bit more error
                                       //to floating point representation of 3.1
BigDecimal b = BigDecimal.valueOf(x2); 
System.out.println(b);

What gets printed out?

3.1000000000000005

We have a 16 digit number when we probably want a 1 digit number.

Another example of floating point imprecision

double x1 = 3.03;   
double x2 = 0;
for(int i = 0; i < 100; i++)
    x2 += x1;
System.out.println(x2);

We added 3.03 to itself to 100 times. Do we get 303? Nope!

302.99999999999966

How many digits would you want to print here?

Community
  • 1
  • 1
Matthew Gunn
  • 4,451
  • 1
  • 12
  • 30
  • 1
    In both cases, you should really apply appropriate rounding. However if you know what this is you can just apply it to the `b` value making this rather tricky to find a good use case for. ;) +1 – Peter Lawrey Nov 25 '15 at 17:58
2

I suspect this isn't as meaningful as you think but you can do this with BigDecimal

static String formatNumber(double b, double example) {
    return BigDecimal.valueOf(b).setScale(
                         BigDecimal.valueOf(example).scale(), 
                         RoundingMode.HALF_UP)
                     .toString();
}

This will give one number the scale which would be used for another.

Note the scale for

3.03 or 3.0300000 is 2
3 or 3.0 or 3.00000 is 1
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • This may work okay if 'example' is a hard coded constant whenever the function is called. Otherwise, I'd worry about floating point error causing weird behavior. – Matthew Gunn Nov 25 '15 at 11:42
  • @MatthewGunn double's representation error isn't a random error. It is predicable and consistent. However, I agree that if you pass any value which is computed without rounding, it is likely the scale will just be to the precision of `double` and this method won't really do anything. – Peter Lawrey Nov 25 '15 at 17:57
  • 1
    yeah, so if he just uses hard coded constants for the double `a` determining the format, I think he's fine. Also, if he does some rounding, he's probably fine. I thought I should bring up issues with floating point precision because: (i) several answers hadn't mentioned it, and (ii) it could cause horribly confusing bugs if one naively thought that doubles represented numbers perfectly. – Matthew Gunn Nov 25 '15 at 18:32
0

Or Something like this :

    String number_1 = String.valueOf(3.03);
    double number_2 = 100.2397;
    String replace=number_1.replaceAll("\\d", "#");
    DecimalFormat df2 = new DecimalFormat(replace);

    double dd2dec = Double.parseDouble(df2.format(number_2));
    System.out.println(dd2dec);

O/P:

100.24
Madushan Perera
  • 2,568
  • 2
  • 17
  • 36
0

The number 3.03, when it is stored in a double, is stored as 8 bytes, 64 bits. This is the whole value:

01000000_00001000_00111101_01110000_10100011_11010111_00001010_00111101

Those bits include the number's mantissa, sign and exponent. There is nothing in it that indicates format. There is no place for that in 8 bytes of information.

When you print a double using, for example, System.out.print, it's the print method that decides how many digits to print, based on the ability to distinguish this number from the nearest double numbers. Thus, print decides on the format - it's not stored in the number.

But you can decide which format you want to print a number in, by using a Formatter (e.g. System.out.printf, which uses a Formatter) or a DecimalFormat.

You decide on the format in this case. It has nothing to do with the number. For example, using

System.out.printf("%7.3f%n",a);

you'll get the result

  3.030

Using it on your b will result in

 56.093

So you can dictate the format, but it's not decided by the number. It's decided by the "%7.3f" format.

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
  • I understand that there is not any format information included in the primitive type double! I was wondering if there was some kind of functionality in any of Javas Libraries that "calculates" the format of a given number and formats another number with it. This could have been done by removing removing all the trailing zeroes and then count the remaining ones. I have understood now that there is no such functionality so I have to implement it myself - but it could most definetly have been done. And in that case I would use that instead of an implementation I wrote myself. – Joakim Nov 25 '15 at 10:49
  • @Joakim I think the reason that there is no such functionality is that it's not very useful. Although the decision Java makes for formatting a number is documented, it is rather arbitrary, and different than other programming languages. It's much more useful that programmers or users will decide for themselves the format they want to see, and thus there is no library call for this rather unusual requirement. – RealSkeptic Nov 25 '15 at 11:04