1

Can I reduce the precision of a float number? In all the searching I've been doing I saw only how to reduce the precision for printing the number. I do not need to print it. I want, for example, to convert 13.2836 to 13.28. Without even rounding it.

Is it possible?


The suggested answer from the system is not what I am looking for. It also deals with printing the value and I want to have a float.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
dushkin
  • 1,939
  • 3
  • 37
  • 82

4 Answers4

2

There isn't really a way to do it, with good reason. While john16384's answer alludes to this, his answer doesn't make the problem clear... so probably you'll try it, it won't do what you want, and perhaps you still won't know why...

The problem is that while we think in decimal and expect that the decimal point is controlled by a power-of-10 exponent, typical floating point implementations (including Java float) use a power-of-2 exponent. Why does it matter?

You know that to represent 1/3 in decimal you'd say 0.3(repeating) - so if you have a limited number of decimal digits, you can't really represent 1/3. When the exponent is 2 instead of 10, you can't really represent 1/5 either, or a lot of other numbers that you could represent exactly in decimal.

As it happens .28 is one of those numbers. So you could multiply by 100, pass the result to floor, and divide by 100, but when this gets converted back to a float, the resulting value will be a little different from .28 and so, if you then check its value, you'll still see more than 2 decimal places.

The solution would be to use something like BigDecimal that can exactly represent decimal values of a given precision.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • Although I completely agree with this, I think there are also valid cases where one just wants to round a float -- converting a float calculation to the nearest integer for example is the most common case of rounding yet I donot see people saying one shouldn't do `(int)f`. I don't think it is too far fetched that there are cases where one wants to round it to a multiple of 0.01 in this case or to some other multiple (to convert to 1/3 subpixels or something). – john16384 Feb 28 '17 at 08:34
  • If an application calls for the closest `float` value to what you'd get by rounding to multiples of .01, then `floor(n*x)/x` is fine. However, that's a different problem from rounding or truncating to a number of digits. It's not about what you "should" do with a `float`; it's about what you *can* do with one. Nobody complains about `(int)f` because `(int)f` returns the exact value you'd expect it to return. – Mark Adelsberger Feb 28 '17 at 13:26
  • Try this: `float f = 16777217` and cast it to an int. Floats being only 32 bit with part of them dedicated to the exponent cannot possibly represent all 32-bit ints. – john16384 Feb 28 '17 at 15:05
  • I didn't say `(float)i` would work for arbitrary integer `i`. I said `(int)f` will work. Nice straw man, though. – Mark Adelsberger Feb 28 '17 at 15:11
  • And before you start: I'm also aware that you could create a very large `float` value that would not cast cleanly to `int`; but as you're perfectly well aware, that's not what we were talking about, since such a value would not have a fractional part to round. – Mark Adelsberger Feb 28 '17 at 15:14
1

The standard warnings about doing precision arithmetic with floats applies, but you can do this:

float f = 13.2836;

f = Math.floor(f * 100) / 100;
john16384
  • 7,800
  • 2
  • 30
  • 44
1

if you need to save memory in some part of your calculation, And your numbers are smaller than 2^15/100 (range short), you can do the following. Part of this taken from this post https://stackoverflow.com/a/25201407/7256243.

float number = 1.2345667f; 
number= (short)(100*number);
number=(float)(number/100);

You only need to rememeber that the short's are 100 times larger.

Community
  • 1
  • 1
1

Most answers went straight to how do represent floats more accurately, which is strange because you're asking:

Can I reduce the precision of a float number

Which is the exact opposite. So I'll try to answer this.

However there are several way to "reduce precision":

  • Reduce precision to gain performance
  • Reduce memory footprint
  • Round / floor arbitrarily
  • Make the number more "fuzzy"
  • Reduce the number of digits after the coma

I'll tackle those separately.


Reduce precision to gain performance

Just to get it out of the way: simply because you're dropping precision off of your calculations on a float, doesn't mean it'll be any faster. Quite the contrary. This answer by @john16384:

f = Math.floor(f * 100) / 100;

Only adds up computation time. If you know the number of significant digits from the result is low, don't bother removing them, just carry that information with the number:

public class Number WithSignificantDigits {
    private float value;
    private int significantdigits;

    (implement basic operations here, but don't floor/round anywhere)
}

If you're doing this because you're worried about performance: stop it now, just use the full precision. If not, read on.


Reduce memory footprint

To actually store a number with less precision, you need to move away from float.

One such representation is using an int with a fixed point convention (i.e. the last 2 digits are past the coma).

If you're trying to save on storage space, do this. If not, read on.


Round / floor arbitrarily

To keep using float, but drop its precision, several options exist:

@john16384 proposed:

`f = Math.floor(f * 100) / 100;`

Or even

f = ((int) (f*100)) / 100.;

If the answer is this, your question is a duplicate. If not, read on.


Make the number more "fuzzy"

Since you just want to lose precision, but haven't stated how much, you could do with bitwise shifts:

float v = 0;
int bits = Float.floatToIntBits(v);
bits = bits >> 7; // Precision lost here
float truncated = Float.intBitsToFloat(bits);

Use 7 bitshifts to reduce precision to nearest 1/128th (close enough to 1/100)
Use 10 bitshifts to reduce precision to nearest 1/1024th (close enough to 1/1000)

I haven't tested performance of those, but If your read this, you did not care.

If you want to lose precision, and you don't care about formatting (numbers may stil have a large number of digits after the coma, like 0,9765625 instead of 1), do this. If you care about formatting and want a limited number of digits after the coma, read on.


Reduce the number of digits after the coma

For this you can:

  • Follow @Mark Adelsberger's suggestion of BigDecimals, or
  • Store as a String (yuk)

Because floats or doubles won't let you do this in most cases.

MrBrushy
  • 680
  • 3
  • 17
  • Actually, the other answers went straight to answering the question asked (how to get a value truncated to N digits), rather than the similar question we wanted to answer. – Mark Adelsberger Feb 28 '17 at 15:29
  • @MarkAdelsberger It's funny because I feel my answer adds value, if you read the Q *as it is written*. Rounding/Flooring are obviously duplicates, so I went for other interpretations like fuzzying or alternate storage systems. Of course, since the *question* was vague, I should have asked for more precisions in the comments. Then I wouldn't have wasted my time. I was foolishly thinking OP meant what he wrote (`reducing precision`) when all he wanted was merely truncate. That'll teach me. – MrBrushy Mar 01 '17 at 17:28
  • It's funny that you think you own the language, such that what you thought he meant is "what he wrote" in spite of the fact that so many other people saw the same words and knew what he meant. – Mark Adelsberger Mar 01 '17 at 17:31
  • 1
    Very strange and abrupt comment when I was but going your way. I do not claim to 'own' anything and you do not know what I think, please stay civil. I think we agree on a certain level. But we *have* to make do with what is *written*, that's how SO works. It is common practice to edit a question to *not* follow the author's mind (because it might be a dupe like this one is) but instead to clarify it into an alternative & interesting question that would deserve to exist on SO. Wouldn't you agree? You saw value in this question, as you answered it. Can't we make it a better Q, as a community? – MrBrushy Mar 01 '17 at 18:00