1

I suddenly had a need to just chop off the excessive digits off of a float number, so I looked in the toolbox and saw that DecimalFormat was available.

Though creating a new object just to chop off some extra digits off a number seemed rather expensive, so I threw together a small program to test it.

public class Snippet {

    static float unformatted = -542.347543274623876F;
    static int fractionDigits = 2;

    public static void main(String[] args){

        long a = System.nanoTime();
        System.out.println(stringMethod(unformatted));
        long b = System.nanoTime();
        System.out.println(formatMethod(unformatted));
        long c = System.nanoTime();
        System.out.println(stringMethod2(unformatted));
        long d = System.nanoTime();

        System.out.println("OP1:"+(b-a));
        System.out.println("OP2:"+(c-b));
        System.out.println("OP3:"+(d-c));

    }

    private static float stringMethod(float number){
        String unfStr = String.valueOf(number);
        for(int i=0;i<unfStr.length();i++){
            if(unfStr.charAt(i) == '.'){
                return Float.parseFloat(unfStr.substring(0, i+1+fractionDigits));
            }
        }
        return Float.parseFloat(unfStr);
    }

    private static float stringMethod2(float number){
        String unfStr = String.format("%."+(fractionDigits+1)+"f",number);
        return Float.parseFloat(unfStr.substring(0,unfStr.length()-1));
    }

    private static float formatMethod(float number){
        DecimalFormat df = new DecimalFormat();
        df.setMaximumFractionDigits(fractionDigits);
        df.setRoundingMode(RoundingMode.DOWN);
        return Float.parseFloat(df.format(unformatted));
    }

}

OUTPUT:

-542.34
-542.34
-542.34
OP1:1937181
OP2:32609426
OP3:3111908

No matter how many times I run it, the DecimalFormat method just can't keep up.

So I guess the question here is, is there any reason (apart from code readability) to use DecimalFormat instead of creating your own method for simple float truncation?

Ceiling Gecko
  • 3,104
  • 2
  • 24
  • 33
  • 1
    [How do I write a correct micro-benchmark in Java?](http://stackoverflow.com/q/504103) – Tom Feb 02 '15 at 22:10
  • 2
    Are you **sure** you should be using float rather than BigDecimal? Note that once you do your parseFloat, there really are extra decimal places, even if you don't always see them. The closest float to -542.34 is -542.34002685546875. – Patricia Shanahan Feb 02 '15 at 22:14
  • 1
    Your benchmarks are irrelevant - even in a non-JIT compiled language you need to run a few thousand iterations; in a JIT compiled language, things are more ... complicated. Moreover, creating a `DecimalFormat` isn't free - do that once, outside of the benchmarked code. – Boris the Spider Feb 02 '15 at 22:14
  • Your declaration itself is flawed. `-542.347543274623876F` is equal to `-542.34753` and even using double isn't enough, since `-542.347543274623876d` is equal to `-542.3475432746238`. You need more precision if any of this is going to be accurate. Example here: http://ideone.com/wIhBpL – mbomb007 Feb 02 '15 at 22:50
  • You only have two choices: `DecimalFormat` or `BigDecimal`. You won't convince me that decimal formatting is a rate-determining step in your application. – user207421 Feb 02 '15 at 22:57
  • @CeilingGecko Don't forget to select an answer so the question can be closed. Or did that not answer it for you? – mbomb007 Feb 09 '15 at 20:39

1 Answers1

0

This is a numerical way to do it:

double d = -542.347543274623876;
System.out.println(d);
int n = 2; // decimal digits

double p = Math.pow(10,n);
d = Math.floor((int)(p*d))/p;
System.out.println(d);

Try it here: http://ideone.com/wIhBpL

What it does, it to multiply it by 10 times the number of decimal digits you want, convert it to an integer (which chops off the remaining digits), then convert it back to a decimal by dividing by 10 times the number of decimal digits. It should work for float, too, if you use that instead.

mbomb007
  • 3,788
  • 3
  • 39
  • 68
  • This is of course assuming that your `double` or `float` can actually _hold_ the value with two decimal places - which may well not be the case. – Boris the Spider Feb 03 '15 at 17:47
  • @BoristheSpider, the OP says it's a `float`, and if it starts as a floating point, then since it ends with less precision, it will end fitting within a floating point number. I showed it with a `double`, since the OP's first assignment statement resulted in a large loss of precision. – mbomb007 Feb 03 '15 at 21:53
  • @BoristheSpider, The question does not request arbitrary precision, so why use a string? – mbomb007 Feb 03 '15 at 21:54