Issue
I'm a new computer science student and we were given an assignment. Write a code that converts degrees from Celsius to to Fahrenheit. Writing the code was no real problem.
but when I used float as a data type, the calculation yielded a more accurate answer than when using double, even thou, to my understanding, it should be the other way around. Does anyone have any idea why? I tried to look it up but nothing came up. Thanks!
//initializing variables.
Scanner takeDegInCel=new Scanner (System.in);
final float constant1InF=1.8f, constant2InF=32.f;
final double constant1InD=1.8, constant2InD=32;
float degInCelF, resInFahrF;
double degInCelD, resInFahrD;
//taking user input.
System.out.print("Enter degrees in Celsius using float type: ");
degInCelF= takeDegInCel.nextFloat();
System.out.print("Enter degrees in Celsius using double type: ");
degInCelD= takeDegInCel.nextDouble();
//calculating degrees in fahrenheit and printing it in a FLOAT
resInFahrF = (constant1InF*degInCelF)+constant2InF;
System.out.print("Degrees in Fahrenheit using float: " + resInFahrF);
//calculating degrees in farenheit and printing it in a DOUBLE
resInFahrD = (constant1InD*degInCelD)+constant2InD;
System.out.print(" \n \nDegrees in Fahrenheit using double: " + resInFahrD);
takeDegInCel.close();
the output using the float variable, given the input 33, is 91.399994.
the output using the double variable, for input 33, is 91.4.
I would expect these two to be reversed.
Solution
Having a result that presents just more digits after dot doesn't mean that the result is more precise.
Actually, the result for float "91.399994" in which you see more digits after dot for the Float calculation is exactly the effect of Float being less accurate than double, so you get a result that is approximation, while using Double you get the "exact" "91.4" result (this actually is just because of luck that Double can actually represent this exact number).
All calculations done using Float or Double should be treated as approximations, because of the distribution of the numbers, not all possible "real" numbers are possible to be stored using Float or Double, so the result of these calculations should ALWAYS bet treated as approximation. Float and Double shouldn't be used for most money calculations beacause of this (eg. tax, account balance etc, because this float/double rounding effect can add or remove some amount - the bigger the number the bigger the "rounding" effect), these types are good for scientific calculations where approximations are good enough. Double is more precise than float, so you can get more precise result if desired. If you need bigger precision than Double (eg. do some exact money calculations), you can use BigDecimal, but although you can get almost any arbitrary precision for BigDecimal, the result is also approximation to some degree. this is because todays computers don't have infinite memory to store the exact value. For instance, you can't store the full real value of 1/3 neither in Float, Double or BigDecimal. Usually bigger precision means slower calculations.
On most of modern computers Double/Float calculations have same speed, just different memory usage. BigDecimal is differnet, it does calculations programatically, so it gets slower with size. you can check it here: double or float, which is faster?
There are very good articles that explain in depth the nature of Double and Float numbers, from these you can read:
PRECISION FOR FLOAT:
Float number structure: /1 bit sign/8 bits exponent/23 bits fraction/
Precision limitations on decimal values in [1, 16777216]
Decimals between 1 and 2: fixed interval 2^−23 (1+2^−23 is the next largest float after 1)
Decimals between 2 and 4: fixed interval 2^−22
Decimals between 4 and 8: fixed interval 2^−21
...
Decimals between 2^n and 2^(n+1): fixed interval 2n-23
...
Decimals between 2^22=4194304 and 2^23=8388608: fixed interval 2^−1=0.5
Decimals between 2^23=8388608 and 2^24=16777216: fixed interval 2^0=1
Precision limitations on integer values
Integers between 0 and 16777216 can be exactly represented (also applies for negative integers between −16777216 and 0)
Integers between 2^24=16777216 and 2^25=33554432 round to a multiple of 2 (even number)
Integers between 2^25 and 2^26 round to a multiple of 4
...
Integers between 2n and 2n+1 round to a multiple of 2^(n-23)
...
Integers between 2^127 and 2^128 round to a multiple of 2^104
Integers greater than or equal to 2^128 are rounded to "infinity".
PRECISION FOR DOUBLE:
Double number structure: /1 bit sign/11 bits exponent/52 bits fraction/
Precision limitations on integer values
Integers from −2^53 to 2^53 (−9,007,199,254,740,992 to 9,007,199,254,740,992) can be exactly represented
Integers between 2^53 and 2^54 = 18,014,398,509,481,984 round to a multiple of 2 (even number)
Integers between 2^54 and 2^55 = 36,028,797,018,963,968 round to a multiple of 4
Interesting fact is that all the values of Integer (4 bytes) can be stored in Double (8 bytes) as exact integrals without loosing precision.
this means that after doing:
int x = //some random value
double d = (double)x;
int y= (int)d;
the x and y will always be the same;
This might have importance if for instance you export data from db to xlsx format, xlsx offers only double precision for cells of type number. For instance if you put some IDs in a column of type Number then if these IDs are in the range of Integer then they will be ok as numbers, otherwise they need to be stored as text. Most IDs in databases usually is stored as long, so most likely they need to be stored as text in xlsx.
sources:
https://en.wikipedia.org/wiki/Single-precision_floating-point_format
https://en.wikipedia.org/wiki/Double-precision_floating-point_format
Answered By - Krzysztof Cichocki