As the title states, I'm trying to convert some floats to ints and there are a few anomalies i saw for a couple of values. I have a method that's trying to convert the decimal portion of a float, for example .45 from 123.45, to a string representation where it outputs as 45/100.
The problem is that for 0.35, 0.45, 0.65 and 0.95 i get 0.34, 0.44, 0.64 and 0.94 respectively. Here's my implementation:
public String convertDecimalPartToString(float input){
int numberOfDigits = numberOfDigits(input);
System.out.println(numberOfDigits);
String numerator = Integer.toString((int) (input * Math.pow(10, numberOfDigits)));
String denominator = Integer.toString((int) Math.pow(10, numberOfDigits));
return numerator + "/" + denominator;
}
public int numberOfDigits(float input){
String inputAsString = Float.toString(input);
System.out.println(inputAsString);
int digits = 0;
// go to less than 2 because first 2 will be 0 and .
for(int i =0;i<inputAsString.length()-2;i++){
digits++;
}
return digits;
}
My test method looks like this:
#Test
public void testConvertDecimalPartToString(){
float input = 0.95f;
//output is 94/100 and assert fails
Assert.assertEquals("95/100", checkWriter.convertDecimalPartToString(input));
}
It seems like there's a miscalculation in this line:
String numerator = Integer.toString((int) (input * Math.pow(10, numberOfDigits)));
but I don't understand why it works properly for 0.05, 0.15, 0.25, 0.55, 0.75 and 0.85.
Can anybody help me understand?
The problem is blessed numbers. Imagine I gave you 3 bits (0 or 1 values): you could only represent 8 different values with this: 000, 001, 010, 011, 100, 101, 110, and 111. That's all of em. Can't represent more than 8 concepts if that's the only legal values!
float is a 32-bit value. With 32 bits, I can give you up to 4 billion different values. That's a lot of values, but it is not infinite, and yet there are infinite numbers between 0 and 1, let alone between 0 and 340,282,346,638,528,860,000,000,000,000,000,000,000.000000 which is the largest value a float can represent.
So how does that work? Well, not every number is actually representable. Only about 4 billion numbers are. These are the blessed numbers.
Anytime you try to make a non-blessed number, or the result of a calculation isn't blessed, then your number is rounded to the nearest blessed number, and if you perform a sequence of operations, that rounding occurs at every step.
The nature of blessed numbers is such that there are as many blessed numbers beteen 0 and 1 as there are above 1 - as you move away from 0 the interval between any 2 blessed numbers goes up. Eventually it'll be more than 1.0, in fact.
Furthermore, computers count in binary, not decimal. Just like you cannot represent '1 divided amongst 3 things' in decimal (0.33333... it never ends), something as simple as 0.1 (1 divided amongst 10 things) cannot be perfectly represented in binary, so something as simple as 1.0/10.0 already rounds!
Your code will fail if _any_rounding occurs. The solution in your case is fairly easy; add 0.005 would do it. A better way is to first render it to a rounded string:
String x = String.format("%.02f", yourValue);
and then find what you need in the string. The above takes care of proper rounding and will do a better job than using Math.pow, which, as it moves you away from that 0, causes MORE errors to show up (further from 0 -> more extreme rounding errors, as there are fewer blessed numbers out that far).
NB: Note that double is as fast as float, and given that you have 64 bits to spend there, has way more blessed numbers, so, fewer errors.
NB2: Another way to do this is to just move your concept of a 'unit'. For example, if this represents cash, just have int cents; - no problems there, it's much easier to know what the blessed numbers are for int (every integer between -2^31 and +2^31).
Related
I am working on a code where I am comparing Double and float values:
class Demo {
public static void main(String[] args) {
System.out.println(2.0 - 1.1); // 0.8999999999999999
System.out.println(2.0 - 1.1 == 0.9); // false
System.out.println(2.0F - 1.1F); // 0.9
System.out.println(2.0F - 1.1F == 0.9F); // true
System.out.println(2.0F - 1.1F == 0.9); // false
}
}
Output is given below:
0.8999999999999999
false
0.9
true
false
I believe the Double value can save more precision than the float.
Please explain this, looks like the float value is not lose precision but the double one lose?
Edit:
#goodvibration I'm aware of that 0.9 can not be exactly saved in any computer language, i'm just confused how java works with this in detail, why 2.0F - 1.1F == 0.9F, but 2.0 - 1.1 != 0.9, another interesting found may help:
class Demo {
public static void main(String[] args) {
System.out.println(2.0 - 0.9); // 1.1
System.out.println(2.0 - 0.9 == 1.1); // true
System.out.println(2.0F - 0.9F); // 1.1
System.out.println(2.0F - 0.9F == 1.1F); // true
System.out.println(2.0F - 0.9F == 1.1); // false
}
}
I know I can't count on the float or double precision, just.. can't figure it out drive me crazy, whats the real deal behind this? Why 2.0 - 0.9 == 1.1 but 2.0 - 1.1 != 0.9 ??
The difference between float and double:
IEEE 754 single-precision binary floating-point format
IEEE 754 double-precision binary floating-point format
Let's run your numbers in a simple C program, in order to get their binary representations:
#include <stdio.h>
typedef union {
float val;
struct {
unsigned int fraction : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
} bits;
} F;
typedef union {
double val;
struct {
unsigned long long fraction : 52;
unsigned long long exponent : 11;
unsigned long long sign : 1;
} bits;
} D;
int main() {
F f = {(float )(2.0 - 1.1)};
D d = {(double)(2.0 - 1.1)};
printf("%d %d %d\n" , f.bits.sign, f.bits.exponent, f.bits.fraction);
printf("%lld %lld %lld\n", d.bits.sign, d.bits.exponent, d.bits.fraction);
return 0;
}
The printout of this code is:
0 126 6710886
0 1022 3602879701896396
Based on the two format specifications above, let's convert these numbers to rational values.
In order to achieve high accuracy, let's do this in a simple Python program:
from decimal import Decimal
from decimal import getcontext
getcontext().prec = 100
TWO = Decimal(2)
def convert(sign, exponent, fraction, e_len, f_len):
return (-1) ** sign * TWO ** (exponent - 2 ** (e_len - 1) + 1) * (1 + fraction / TWO ** f_len)
def toFloat(sign, exponent, fraction):
return convert(sign, exponent, fraction, 8, 23)
def toDouble(sign, exponent, fraction):
return convert(sign, exponent, fraction, 11, 52)
f = toFloat(0, 126, 6710886)
d = toDouble(0, 1022, 3602879701896396)
print('{:.40f}'.format(f))
print('{:.40f}'.format(d))
The printout of this code is:
0.8999999761581420898437500000000000000000
0.8999999999999999111821580299874767661094
If we print these two values while specifying between 8 and 15 decimal digits, then we shall experience the same thing that you have observed (the double value printed as 0.9, while the float value printed as close to 0.9):
In other words, this code:
for n in range(8, 15 + 1):
string = '{:.' + str(n) + 'f}';
print(string.format(f))
print(string.format(d))
Gives this printout:
0.89999998
0.90000000
0.899999976
0.900000000
0.8999999762
0.9000000000
0.89999997616
0.90000000000
0.899999976158
0.900000000000
0.8999999761581
0.9000000000000
0.89999997615814
0.90000000000000
0.899999976158142
0.900000000000000
Our conclusion is therefore that Java prints decimals with a precision of between 8 and 15 digits by default.
Nice question BTW...
Pop quiz: Represent 1/3rd, in decimal.
Answer: You can't; not precisely.
Computers count in binary. There are many more numbers that 'cannot be completely represented'. Just like, in the decimal question, if you have only a small piece of paper to write it on, you may simply go with 0.3333333 and call it a day, and you'd then have a number that is quite close to, but not entirely the same as, 1 / 3, so do computers represent fractions.
Or, think about it this way: a float occupies 32-bits; a double occupies 64. There are only 2^32 (about 4 billion) different numbers that a 32-bit value can represent. And yet, even between 0 and 1 there are an infinite amount of numbers. So, given that there are at most 2^32 specific, concrete numbers that are 'representable precisely' as a float, any number that isn't in that blessed set of about 4 billion values, is not representable. Instead of just erroring out, you simply get the one in this pool of 4 billion values that IS representable, and is the closest number to the one you wanted.
In addition, because computers count in binary and not decimal, your sense of what is 'representable' and what isn't, is off. You may think that 1/3 is a big problem, but surely 1/10 is easy, right? That's simply 0.1 and that is a precise representation. Ah, but, a tenth works well in decimal. After all, decimal is based around the number 10, no surprise there. But in binary? a half, a fourth, an eighth, a sixteenth: Easy in binary. A tenth? That is as difficult as a third: NOT REPRESENTABLE.
0.9 is, itself, not a representable number. And yet, when you printed your float, that's what you got.
The reason is, printing floats/doubles is an art, more than a science. Given that only a few numbers are representable, and given that these numbers don't feel 'natural' to humans due to the binary v. decimal thing, you really need to add a 'rounding' strategy to the number or it'll look crazy (nobody wants to read 0.899999999999999999765). And that is precisely what System.out.println and co do.
But you really should take control of the rounding function: Never use System.out.println to print doubles and floats. Use System.out.printf("%.6f", yourDouble); instead, and in this case, BOTH would print 0.9. Because whilst neither can actually represent 0.9 precisely, the number that is closest to it in floats (or rather, the number you get when you take the number closest to 2.0 (which is 2.0), and the number closest to 1.1 (which is not 1.1 precisely), subtract them, and then find the number closest to that result) – prints as 0.9 even though it isn't for floats, and does not print as 0.9 in double.
I want to find an effiecient way of making sure that the number of decimal places in
double is not more than three.
double num1 = 10.012; //True
double num2 = 10.2211; //False
double num2 = 10.2; //True
Currently, what I do is just use a regex split and count index of . like below.
String[] split = new Double(num).toString().split("\\.")
split[0].length() //num of decimal places
Is there an efficient or better way to do this since I'll be calling this
function a lot?
If you want a solution that will tell you that information in a way that will agree with the eventual result of converting the double to a string, then efficiency doesn't really come into it; you basically have to convert to string and check. The result is that it's entirely possible for a double to contain a value that mathematically has a (say) non-zero value in (say) the hundred-thousandth place, but which when converted to string will not. Such is the joy of IEEE-754 double-precision binary floating point: The number of digits you get from the string representation is only as many as necessary to distinguish the value from its adjacent representable value. From the Double docs:
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
But if you're not concerned about that, and assuming limiting your value range to long is okay, you can do something like this:
private static boolean onlyThreePlaces(double v) {
double d = (double)((long)(v * 1000)) / 1000;
return d == v;
}
...which should have less memory overhead than a String-round-trip.
However, I'd be surprised if there weren't a fair number of times when that method and the result of Double.toString(double) didn't match in terms of digits after the decimal, for the reasons given above.
In a comment on the question, you've said (when I asked about the value range):
Honestly I'm not sure. I'm dealing with prices; For starters, I'll assume 0-200K
Using double for financial values is usually not a good idea. If you don't want to use BigDecimal because of memory concerns, pick your precision and use int or long depending on your value range. For instance, if you only need to-the-penny precision, you'd use values multiplied by 100 (e.g., 2000 is Ⓠ20 [or whatever currency you're using, I'm using Ⓠ for quatloos]). If you need precision to thousanths of a penny (as your question suggests), then multiply by 100000 (e.g., 2000000 is Ⓠ20). If you need more precision, pick a larger multiplier. Even if you go to hundred-thousanths of a penny (muliplier: 10000000), with long you have a range of Ⓠ-922,337,203,685 to Ⓠ922,337,203,685.
This has the side-benefit that it makes this check easier: Just a straight %. If your multiplier is 10000000 (hundred-thousandths of a penny), it's just value % 10000 != 0 to identify invalid ones (or value % 10000 == 0 to identify valid ones).
long num1 = 100120000; // 10.012 => true
// 100120000 % 10000 is 0 = valid
long num2 = 102211000; // 10.2211 => false
// 102211000 % 10000 is 1000 = invalid
long num3 = 102000000; // 10.2 => true
// 102000000 % 10000 is 0 = valid
Terminology
In this question I am calling "floating point number" "decimal number" to prevent ambiguation with the float/double Java primitive data types. The term "decimal" has no relationship with "base 10".
Background
I am expressing a decimal number of any base in this way:
class Decimal{
int[] digits;
int exponent;
int base;
int signum;
}
which approximately expresses this double value:
public double toDouble(){
if(signum == 0) return 0d;
double out = 0d;
for(int i = digits.length - 1, j = 0; i >= 0; i--, j++){
out += digits[i] * Math.pow(base, j + exponent);
}
return out * signum;
}
I am aware that some conversions are not possible. For example, it is not possible to convert 0.1 (base 3) to base 10, because it is a recurring decimal. Similarly, converting 0.1 (base 9) to base 3 is not possible, but covnerting 0.3 (base 3) is possible. There are probably other cases that I have not considered.
The traditional way
The traditional way (by hand) of change of base, for integers, from base 10 to base 2, is to divide the number by the exponents of 2, and from base 2 to base 10 is to multiply the digits by respective exponents of 2. Changing from base x to base y usually involves converting to base 10 as an intermediate.
First question: Argument validation
Therefore, my first question is, if I were to implement the method public Decimal Decimal.changeBase(int newBase), how can I validate whether newBase can be made without resulting in recurring decimals (which is incompatible with the design of the int[] digits field, since I don't plan to make an int recurringOffset field just for this.
Second question: Implementation
Hence, how to implement this? I instinctively feel that this question is much easier to solve if the first question is solved.
Third question: What about recurring number output:
I don't plan to make an int recurringOffset field just for this.
For the sake of future readers, this question should also be asked.
For example, according to Wolfram|Alpha:
0.1 (base 4) = 0.[2...] (base 9)
How can this be calculated (by hand, if by programming sounds too complicated)?
I think that a data structure like this can represent this decimal number:
class Decimal{
int[] constDigits;
int exponent;
int base;
int signum;
#Nullable #NonEmpty int[] appendRecurring;
}
For example, 61/55 can be expressed like this:
{
constDigits: [1, 1], // 11
exponent: -1, // 11e-1
base: 10,
signum: 1, // positive
appendRecurring: [0, 9]
}
Not a homework question
I am not looking for any libraries. Please do not answer this question with reference to any libraries. (Because I'm writing this class just for fun, OK?)
To your first question: whenever the prime factors of the old base are also among the prime factors of the new base you can always convert without becoming periodic. For example every base 2 number can be represented exactly as base 10. This condition is unfortunately sufficient but not necessary, for example there are some base 10 numbers like 0.5 that can be represented exactly as base 2, although 2 does not have the prime factor 5.
When you write the number as fraction and reduce it to lowest terms it can be represented exactly without a periodic part in base x if and only if the denominator has only prime factors that also appear in x (ignoring exponents of primes).
For example, if your number is 3/25 you can represent this exactly in every base that has a prime factor 5. That is 5, 10, 15, 20, 25, ...
If the number is 4/175, the denominator has prime factors 5 and 7 and therefore can be represented exactly in base 35, 70, 105, 140, 175, ...
For implementation, you can either work in the old base (basically doing divisions) or in the new base (basically doing multiplications). I would avoid going through a third base during the conversion.
Since you added periodic representations to your question the best way for conversion seems to be to convert the original representation to a fraction (this can always be done, also for periodic representations) and then convert this to the new representation by carrying out the division.
To answer the third part of the question, once you have your fraction reduced (and you found out that the "decimal" expansion will be a recurring fraction), you can detect the recurring part by simply doing the long-hand division and remembering the remainders you've encountered.
For example to print out 2/11 in base 6, you do this:
2/11 = 0 (rem 2/11)
2*6/11 = 1 (rem 1/11)
1*6/11 = 0 (rem 6/11)
6*6/11 = 3 (rem 3/11)
3*6/11 = 1 (rem 7/11)
7*6/11 = 3 (rem 9/11)
9*6/11 = 4 (rem 10/11)
10*6/11 = 5 (rem 5/11)
5*6/11 = 2 (rem 8/11)
8*6/11 = 4 (rem 4/11)
4*6/11 = 2 (rem 2/11) <-- We've found a duplicate remainder
(Had 2/11 been convertible to a base 6 number of finite length, we would've reached 0 remainder instead.)
So your result will be 0.[1031345242...]. You can fairly easily design a data structure to hold this, bearing in mind that there could be several digits before the recurrence begins. Your proposed data structure is good for this.
Personally I'd probably just work with fractions, floating point is all about trading in some precision and accuracy for compactness. If you don't want to compromise on precision, floating point is going to cause you a lot of trouble. (Though with careful design you can get pretty far with it.)
I waited with this after the reward because this is not directly an answer to your questions rather few hints how to approach your task instead.
Number format
Arbitrary exponential form of number during base conversion is a big problem. Instead I would convert/normalize your number to form:
(sign) mantissa.repetition * base^exp
Where unsigned int exp is the exponent of least significant digit of mantissa. The mantissa,repetition could be strings for easy manipulation and printing. But that would limit your max base of coarse. For example if you reserve e for exponent then you can use { 0,1,2,..9, A,B,C,...,Z } for digits so max base would be then only 36 (if not counting special characters). If that is not enough stay with your int digit representation.
Base conversion (mantissa)
I would handle mantissa as integer number for now. So the conversion is done simply by dividing mantissa / new_base in the old_base arithmetics. This can be done on strings directly. With this there is no problem as we can always convert any integer number from any base to any other base without any inconsistencies,rounding or remainders. The conversion could look like:
// convert a=1024 [dec] -> c [bin]
AnsiString a="1024",b="2",c="",r="";
while (a!="0") { a=divide(r,a,b,10); c=r+c; }
// output c = "10000000000"
Where:
a is number in old base which you want to convert
b is new base in old base representation
c is number in new base
Used divide function looks like this:
//---------------------------------------------------------------------------
#define dig2chr(x) ((x<10)?char(x+'0'):char(x+'A'-10))
#define chr2dig(x) ((x>'9')?BYTE(x-'A'+10):BYTE(x-'0'))
//---------------------------------------------------------------------------
int compare( const AnsiString &a,const AnsiString &b); // compare a,b return { -1,0,+1 } -> { < , == , > }
AnsiString divide(AnsiString &r,const AnsiString &a, AnsiString &b,int base); // return a/b computed in base and r = a%b
//---------------------------------------------------------------------------
int compare(const AnsiString &a,const AnsiString &b)
{
if (a.Length()>b.Length()) return +1;
if (a.Length()<b.Length()) return -1;
for (int i=1;i<=a.Length();i++)
{
if (a[i]>b[i]) return +1;
if (a[i]<b[i]) return -1;
}
return 0;
}
//---------------------------------------------------------------------------
AnsiString divide(AnsiString &r,const AnsiString &a,AnsiString &b,int base)
{
int i,j,na,nb,e,sh,aa,bb,cy;
AnsiString d=""; r="";
// trivial cases
e=compare(a,b);
if (e< 0) { r=a; return "0"; }
if (e==0) { r="0"; return "1"; }
// shift b
for (sh=0;compare(a,b)>=0;sh++) b=b+"0";
if (compare(a,b)<0) { sh--; b=b.SetLength(b.Length()-1); }
// divide
for (r=a;sh>=0;sh--)
{
for (j=0;compare(r,b)>=0;j++)
{
// r-=b
na=r.Length();
nb=b.Length();
for (i=0,cy=0;i<nb;i++)
{
aa=chr2dig(r[na-i]);
bb=chr2dig(b[nb-i]);
aa-=bb+cy; cy=0;
while (aa<0) { aa+=base; cy++; }
r[na-i]=dig2chr(aa);
}
if (cy)
{
aa=chr2dig(r[na-i]);
aa-=cy;
r[na-i]=dig2chr(aa);
}
// leading zeros removal
while ((r.Length()>b.Length())&&(r[1]=='0')) r=r.SubString(2,r.Length()-1);
}
d+=dig2chr(j);
if (sh) b=b.SubString(1,b.Length()-1);
while ((r.Length()>b.Length())&&(r[1]=='0')) r=r.SubString(2,r.Length()-1);
}
return d;
}
//---------------------------------------------------------------------------
It is written in C++ and VCL. AnsiString is VCL string type with self allocating properties and its members are indexed from 1.
Base conversion (repetition)
There are 2 approaches for this I know of. The simpler but with possible round errors is setting the repetition to long enough string sequence and handle as fractional number. For example rep="123" [dec] then conversion to different base would be done by multiplying by new base in old base arithmetics. So let create long enough sequence:
0 + 0.123123123123123 * 2
0 + 0.246246246246246 * 2
0 + 0.492492492492492 * 2
0 + 0.984984984984984 * 2
1 + 0.969969969969968 * 2
1 + 0.939939939939936 * 2
1 + 0.879879879879872 * 2 ...
------------------------------
= "0.0000111..." [bin]
With this step you need to make repetition analysis and normalize the number again after exponent correction step (in next bullet).
Second approach need to have the repetitions stored as division so you need it in form a/b in old_base. You just convert a,b as integers (the same as mantissa) and then do the division to obtain fractional part + repetition part.
So now you should have converted number in form:
mantissa.fractional [new_base] * old_base^exp
or:
mantissa.fractional+a/b [new_base] * old_base^exp
Base conversion (exponent)
You need to change old_base^old_exp to new_base^new_exp. The simplest way is to multiply the number by the old_base^old_exp value in new base arithmetics. So for starters multiply the whole
mantissa.fractional+(a/b) [new_base]
by old_base old_exp times in the new arithmetics (later you can change it to power by squaring or better). And after that normalize your number. So find where the repetition string begins and its digit position relative to . is the new_exp value.
[Notes]
For this you will need routines to convert old_base and new_base between each other but as the base is not bignum but just simple small unsigned int instead it should not be any problem for you (I hope).
public class doublePrecision {
public static void main(String[] args) {
double total = 0;
total += 5.6;
total += 5.8;
System.out.println(total);
}
}
The above code prints:
11.399999999999
How would I get this to just print (or be able to use it as) 11.4?
As others have mentioned, you'll probably want to use the BigDecimal class, if you want to have an exact representation of 11.4.
Now, a little explanation into why this is happening:
The float and double primitive types in Java are floating point numbers, where the number is stored as a binary representation of a fraction and a exponent.
More specifically, a double-precision floating point value such as the double type is a 64-bit value, where:
1 bit denotes the sign (positive or negative).
11 bits for the exponent.
52 bits for the significant digits (the fractional part as a binary).
These parts are combined to produce a double representation of a value.
(Source: Wikipedia: Double precision)
For a detailed description of how floating point values are handled in Java, see the Section 4.2.3: Floating-Point Types, Formats, and Values of the Java Language Specification.
The byte, char, int, long types are fixed-point numbers, which are exact representions of numbers. Unlike fixed point numbers, floating point numbers will some times (safe to assume "most of the time") not be able to return an exact representation of a number. This is the reason why you end up with 11.399999999999 as the result of 5.6 + 5.8.
When requiring a value that is exact, such as 1.5 or 150.1005, you'll want to use one of the fixed-point types, which will be able to represent the number exactly.
As has been mentioned several times already, Java has a BigDecimal class which will handle very large numbers and very small numbers.
From the Java API Reference for the BigDecimal class:
Immutable,
arbitrary-precision signed decimal
numbers. A BigDecimal consists of an
arbitrary precision integer unscaled
value and a 32-bit integer scale. If
zero or positive, the scale is the
number of digits to the right of the
decimal point. If negative, the
unscaled value of the number is
multiplied by ten to the power of the
negation of the scale. The value of
the number represented by the
BigDecimal is therefore (unscaledValue
× 10^-scale).
There has been many questions on Stack Overflow relating to the matter of floating point numbers and its precision. Here is a list of related questions that may be of interest:
Why do I see a double variable initialized to some value like 21.4 as 21.399999618530273?
How to print really big numbers in C++
How is floating point stored? When does it matter?
Use Float or Decimal for Accounting Application Dollar Amount?
If you really want to get down to the nitty gritty details of floating point numbers, take a look at What Every Computer Scientist Should Know About Floating-Point Arithmetic.
When you input a double number, for example, 33.33333333333333, the value you get is actually the closest representable double-precision value, which is exactly:
33.3333333333333285963817615993320941925048828125
Dividing that by 100 gives:
0.333333333333333285963817615993320941925048828125
which also isn't representable as a double-precision number, so again it is rounded to the nearest representable value, which is exactly:
0.3333333333333332593184650249895639717578887939453125
When you print this value out, it gets rounded yet again to 17 decimal digits, giving:
0.33333333333333326
If you just want to process values as fractions, you can create a Fraction class which holds a numerator and denominator field.
Write methods for add, subtract, multiply and divide as well as a toDouble method. This way you can avoid floats during calculations.
EDIT: Quick implementation,
public class Fraction {
private int numerator;
private int denominator;
public Fraction(int n, int d){
numerator = n;
denominator = d;
}
public double toDouble(){
return ((double)numerator)/((double)denominator);
}
public static Fraction add(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop + bTop, a.denominator * b.denominator);
}
else{
return new Fraction(a.numerator + b.numerator, a.denominator);
}
}
public static Fraction divide(Fraction a, Fraction b){
return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}
public static Fraction multiply(Fraction a, Fraction b){
return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}
public static Fraction subtract(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop-bTop, a.denominator*b.denominator);
}
else{
return new Fraction(a.numerator - b.numerator, a.denominator);
}
}
}
Observe that you'd have the same problem if you used limited-precision decimal arithmetic, and wanted to deal with 1/3: 0.333333333 * 3 is 0.999999999, not 1.00000000.
Unfortunately, 5.6, 5.8 and 11.4 just aren't round numbers in binary, because they involve fifths. So the float representation of them isn't exact, just as 0.3333 isn't exactly 1/3.
If all the numbers you use are non-recurring decimals, and you want exact results, use BigDecimal. Or as others have said, if your values are like money in the sense that they're all a multiple of 0.01, or 0.001, or something, then multiply everything by a fixed power of 10 and use int or long (addition and subtraction are trivial: watch out for multiplication).
However, if you are happy with binary for the calculation, but you just want to print things out in a slightly friendlier format, try java.util.Formatter or String.format. In the format string specify a precision less than the full precision of a double. To 10 significant figures, say, 11.399999999999 is 11.4, so the result will be almost as accurate and more human-readable in cases where the binary result is very close to a value requiring only a few decimal places.
The precision to specify depends a bit on how much maths you've done with your numbers - in general the more you do, the more error will accumulate, but some algorithms accumulate it much faster than others (they're called "unstable" as opposed to "stable" with respect to rounding errors). If all you're doing is adding a few values, then I'd guess that dropping just one decimal place of precision will sort things out. Experiment.
You may want to look into using java's java.math.BigDecimal class if you really need precision math. Here is a good article from Oracle/Sun on the case for BigDecimal. While you can never represent 1/3 as someone mentioned, you can have the power to decide exactly how precise you want the result to be. setScale() is your friend.. :)
Ok, because I have way too much time on my hands at the moment here is a code example that relates to your question:
import java.math.BigDecimal;
/**
* Created by a wonderful programmer known as:
* Vincent Stoessel
* xaymaca#gmail.com
* on Mar 17, 2010 at 11:05:16 PM
*/
public class BigUp {
public static void main(String[] args) {
BigDecimal first, second, result ;
first = new BigDecimal("33.33333333333333") ;
second = new BigDecimal("100") ;
result = first.divide(second);
System.out.println("result is " + result);
//will print : result is 0.3333333333333333
}
}
and to plug my new favorite language, Groovy, here is a neater example of the same thing:
import java.math.BigDecimal
def first = new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")
println "result is " + first/second // will print: result is 0.33333333333333
Pretty sure you could've made that into a three line example. :)
If you want exact precision, use BigDecimal. Otherwise, you can use ints multiplied by 10 ^ whatever precision you want.
As others have noted, not all decimal values can be represented as binary since decimal is based on powers of 10 and binary is based on powers of two.
If precision matters, use BigDecimal, but if you just want friendly output:
System.out.printf("%.2f\n", total);
Will give you:
11.40
You're running up against the precision limitation of type double.
Java.Math has some arbitrary-precision arithmetic facilities.
You can't, because 7.3 doesn't have a finite representation in binary. The closest you can get is 2054767329987789/2**48 = 7.3+1/1407374883553280.
Take a look at http://docs.python.org/tutorial/floatingpoint.html for a further explanation. (It's on the Python website, but Java and C++ have the same "problem".)
The solution depends on what exactly your problem is:
If it's that you just don't like seeing all those noise digits, then fix your string formatting. Don't display more than 15 significant digits (or 7 for float).
If it's that the inexactness of your numbers is breaking things like "if" statements, then you should write if (abs(x - 7.3) < TOLERANCE) instead of if (x == 7.3).
If you're working with money, then what you probably really want is decimal fixed point. Store an integer number of cents or whatever the smallest unit of your currency is.
(VERY UNLIKELY) If you need more than 53 significant bits (15-16 significant digits) of precision, then use a high-precision floating-point type, like BigDecimal.
private void getRound() {
// this is very simple and interesting
double a = 5, b = 3, c;
c = a / b;
System.out.println(" round val is " + c);
// round val is : 1.6666666666666667
// if you want to only two precision point with double we
// can use formate option in String
// which takes 2 parameters one is formte specifier which
// shows dicimal places another double value
String s = String.format("%.2f", c);
double val = Double.parseDouble(s);
System.out.println(" val is :" + val);
// now out put will be : val is :1.67
}
Use java.math.BigDecimal
Doubles are binary fractions internally, so they sometimes cannot represent decimal fractions to the exact decimal.
/*
0.8 1.2
0.7 1.3
0.7000000000000002 2.3
0.7999999999999998 4.2
*/
double adjust = fToInt + 1.0 - orgV;
// The following two lines works for me.
String s = String.format("%.2f", adjust);
double val = Double.parseDouble(s);
System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8
Doubles are approximations of the decimal numbers in your Java source. You're seeing the consequence of the mismatch between the double (which is a binary-coded value) and your source (which is decimal-coded).
Java's producing the closest binary approximation. You can use the java.text.DecimalFormat to display a better-looking decimal value.
Short answer: Always use BigDecimal and make sure you are using the constructor with String argument, not the double one.
Back to your example, the following code will print 11.4, as you wish.
public class doublePrecision {
public static void main(String[] args) {
BigDecimal total = new BigDecimal("0");
total = total.add(new BigDecimal("5.6"));
total = total.add(new BigDecimal("5.8"));
System.out.println(total);
}
}
Multiply everything by 100 and store it in a long as cents.
Computers store numbers in binary and can't actually represent numbers such as 33.333333333 or 100.0 exactly. This is one of the tricky things about using doubles. You will have to just round the answer before showing it to a user. Luckily in most applications, you don't need that many decimal places anyhow.
Floating point numbers differ from real numbers in that for any given floating point number there is a next higher floating point number. Same as integers. There's no integer between 1 and 2.
There's no way to represent 1/3 as a float. There's a float below it and there's a float above it, and there's a certain distance between them. And 1/3 is in that space.
Apfloat for Java claims to work with arbitrary precision floating point numbers, but I've never used it. Probably worth a look.
http://www.apfloat.org/apfloat_java/
A similar question was asked here before
Java floating point high precision library
Use a BigDecimal. It even lets you specify rounding rules (like ROUND_HALF_EVEN, which will minimize statistical error by rounding to the even neighbor if both are the same distance; i.e. both 1.5 and 2.5 round to 2).
Why not use the round() method from Math class?
// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4
Check out BigDecimal, it handles problems dealing with floating point arithmetic like that.
The new call would look like this:
term[number].coefficient.add(co);
Use setScale() to set the number of decimal place precision to be used.
If you have no choice other than using double values, can use the below code.
public static double sumDouble(double value1, double value2) {
double sum = 0.0;
String value1Str = Double.toString(value1);
int decimalIndex = value1Str.indexOf(".");
int value1Precision = 0;
if (decimalIndex != -1) {
value1Precision = (value1Str.length() - 1) - decimalIndex;
}
String value2Str = Double.toString(value2);
decimalIndex = value2Str.indexOf(".");
int value2Precision = 0;
if (decimalIndex != -1) {
value2Precision = (value2Str.length() - 1) - decimalIndex;
}
int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
sum = value1 + value2;
String s = String.format("%." + maxPrecision + "f", sum);
sum = Double.parseDouble(s);
return sum;
}
You can Do the Following!
System.out.println(String.format("%.12f", total));
if you change the decimal value here %.12f
So far I understand it as main goal to get correct double from wrong double.
Look for my solution how to get correct value from "approximate" wrong value - if it is real floating point it rounds last digit - counted from all digits - counting before dot and try to keep max possible digits after dot - hope that it is enough precision for most cases:
public static double roundError(double value) {
BigDecimal valueBigDecimal = new BigDecimal(Double.toString(value));
String valueString = valueBigDecimal.toPlainString();
if (!valueString.contains(".")) return value;
String[] valueArray = valueString.split("[.]");
int places = 16;
places -= valueArray[0].length();
if ("56789".contains("" + valueArray[0].charAt(valueArray[0].length() - 1))) places--;
//System.out.println("Rounding " + value + "(" + valueString + ") to " + places + " places");
return valueBigDecimal.setScale(places, RoundingMode.HALF_UP).doubleValue();
}
I know it is long code, sure not best, maybe someone can fix it to be more elegant. Anyway it is working, see examples:
roundError(5.6+5.8) = 11.399999999999999 = 11.4
roundError(0.4-0.3) = 0.10000000000000003 = 0.1
roundError(37235.137567000005) = 37235.137567
roundError(1/3) 0.3333333333333333 = 0.333333333333333
roundError(3723513756.7000005) = 3.7235137567E9 (3723513756.7)
roundError(3723513756123.7000005) = 3.7235137561237E12 (3723513756123.7)
roundError(372351375612.7000005) = 3.723513756127E11 (372351375612.7)
roundError(1.7976931348623157) = 1.797693134862316
Do not waste your efford using BigDecimal. In 99.99999% cases you don't need it. java double type is of cource approximate but in almost all cases, it is sufficiently precise. Mind that your have an error at 14th significant digit. This is really negligible!
To get nice output use:
System.out.printf("%.2f\n", total);
I have to calculate some floating point variables and my colleague suggest me to use BigDecimal instead of double since it will be more precise. But I want to know what it is and how to make most out of BigDecimal?
A BigDecimal is an exact way of representing numbers. A Double has a certain precision. Working with doubles of various magnitudes (say d1=1000.0 and d2=0.001) could result in the 0.001 being dropped altogether when summing as the difference in magnitude is so large. With BigDecimal this would not happen.
The disadvantage of BigDecimal is that it's slower, and it's a bit more difficult to program algorithms that way (due to + - * and / not being overloaded).
If you are dealing with money, or precision is a must, use BigDecimal. Otherwise Doubles tend to be good enough.
I do recommend reading the javadoc of BigDecimal as they do explain things better than I do here :)
My English is not good so I'll just write a simple example here.
double a = 0.02;
double b = 0.03;
double c = b - a;
System.out.println(c);
BigDecimal _a = new BigDecimal("0.02");
BigDecimal _b = new BigDecimal("0.03");
BigDecimal _c = _b.subtract(_a);
System.out.println(_c);
Program output:
0.009999999999999998
0.01
Does anyone still want to use double? ;)
There are two main differences from double:
Arbitrary precision, similarly to BigInteger they can contain number of arbitrary precision and size (whereas a double has a fixed number of bits)
Base 10 instead of Base 2, a BigDecimal is n*10^-scale where n is an arbitrary large signed integer and scale can be thought of as the number of digits to move the decimal point left or right
It is still not true to say that BigDecimal can represent any number. But two reasons you should use BigDecimal for monetary calculations are:
It can represent all numbers that can be represented in decimal notion and that includes virtually all numbers in the monetary world (you never transfer 1/3 $ to someone).
The precision can be controlled to avoid accumulated errors. With a double, as the magnitude of the value increases, its precision decreases and this can introduce significant error into the result.
If you write down a fractional value like 1 / 7 as decimal value you get
1/7 = 0.142857142857142857142857142857142857142857...
with an infinite repetition of the digits 142857. Since you can only write a finite number of digits you will inevitably introduce a rounding (or truncation) error.
Numbers like 1/10 or 1/100 expressed as binary numbers with a fractional part also have an infinite number of digits after the decimal point:
1/10 = binary 0.0001100110011001100110011001100110...
Doubles store values as binary and therefore might introduce an error solely by converting a decimal number to a binary number, without even doing any arithmetic.
Decimal numbers (like BigDecimal), on the other hand, store each decimal digit as is (binary coded, but each decimal on its own). This means that a decimal type is not more precise than a binary floating point or fixed point type in a general sense (i.e. it cannot store 1/7 without loss of precision), but it is more accurate for numbers that have a finite number of decimal digits as is often the case for money calculations.
Java's BigDecimal has the additional advantage that it can have an arbitrary (but finite) number of digits on both sides of the decimal point, limited only by the available memory.
If you are dealing with calculation, there are laws on how you should calculate and what precision you should use. If you fail that you will be doing something illegal.
The only real reason is that the bit representation of decimal cases are not precise. As Basil simply put, an example is the best explanation. Just to complement his example, here's what happens:
static void theDoubleProblem1() {
double d1 = 0.3;
double d2 = 0.2;
System.out.println("Double:\t 0,3 - 0,2 = " + (d1 - d2));
float f1 = 0.3f;
float f2 = 0.2f;
System.out.println("Float:\t 0,3 - 0,2 = " + (f1 - f2));
BigDecimal bd1 = new BigDecimal("0.3");
BigDecimal bd2 = new BigDecimal("0.2");
System.out.println("BigDec:\t 0,3 - 0,2 = " + (bd1.subtract(bd2)));
}
Output:
Double: 0,3 - 0,2 = 0.09999999999999998
Float: 0,3 - 0,2 = 0.10000001
BigDec: 0,3 - 0,2 = 0.1
Also we have that:
static void theDoubleProblem2() {
double d1 = 10;
double d2 = 3;
System.out.println("Double:\t 10 / 3 = " + (d1 / d2));
float f1 = 10f;
float f2 = 3f;
System.out.println("Float:\t 10 / 3 = " + (f1 / f2));
// Exception!
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4)));
}
Gives us the output:
Double: 10 / 3 = 3.3333333333333335
Float: 10 / 3 = 3.3333333
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion
But:
static void theDoubleProblem2() {
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4, 4, BigDecimal.ROUND_HALF_UP)));
}
Has the output:
BigDec: 10 / 3 = 3.3333
BigDecimal is Oracle's arbitrary-precision numerical library. BigDecimal is part of the Java language and is useful for a variety of applications ranging from the financial to the scientific (that's where sort of am).
There's nothing wrong with using doubles for certain calculations. Suppose, however, you wanted to calculate Math.Pi * Math.Pi / 6, that is, the value of the Riemann Zeta Function for a real argument of two (a project I'm currently working on). Floating-point division presents you with a painful problem of rounding error.
BigDecimal, on the other hand, includes many options for calculating expressions to arbitrary precision. The add, multiply, and divide methods as described in the Oracle documentation below "take the place" of +, *, and / in BigDecimal Java World:
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
The compareTo method is especially useful in while and for loops.
Be careful, however, in your use of constructors for BigDecimal. The string constructor is very useful in many cases. For instance, the code
BigDecimal onethird = new BigDecimal("0.33333333333");
utilizes a string representation of 1/3 to represent that infinitely-repeating number to a specified degree of accuracy. The round-off error is most likely somewhere so deep inside the JVM that the round-off errors won't disturb most of your practical calculations. I have, from personal experience, seen round-off creep up, however. The setScale method is important in these regards, as can be seen from the Oracle documentation.
If you need to use division in your arithmetic, you need to use double instead of BigDecimal. Division (divide(BigDecimal) method) in BigDecimal is pretty useless as BigDecimal can't handle repeating decimal rational numbers (division where divisors are and will throw java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
Just try BigDecimal.ONE.divide(new BigDecimal("3"));
Double, on the other hand, will handle division fine (with the understood precision which is roughly 15 significant digits)