Dart double division precision - dart

What is the correct way to perform this operation?
399.9 / 100
What I would expect to see is
3.999
but the result is
3.9989999999999997

The result you see is correct, it's just not what you want.
Doubles are not precise values. The double you get by writing 399.9 is actually the precise value.
399.8999999999999772626324556767940521240234375
That's the closest available double to the exact value 399.9. Any other double is at least as far away from 399.9 as that.
Then you divide by 100. Again, the result is not precise, but the closest double has the exact value
3.99899999999999966604491419275291264057159423828125
That differs from what you would get by writing 3.999, which is the exact value:
3.999000000000000110134124042815528810024261474609375
At every step, the double operations have minimized the error, but because you are doing multiple steps, the final result diverges from the double closest to the mathematical result.
What you need to do depends on what your actual requirements are.
If you want to always calculate with two significant digits, then I'd just multiply my numbers with 100 and do all the operations as integer operations, until the very last division by 100.
If you have an intermediate result and wants to round it to two digits, I'd do what Fy Z1K says:
result = (result * 100).round() / 100;

import 'dart:math';
double roundDouble(double value, int places){
double mod = pow(10.0, places);
return ((value * mod).round().toDouble() / mod);
}
then you would basically get
double num1 = roundDouble(12.3412, 2);
// 12.34
double num2 = roundDouble(12.5668, 2);
// 12.57
double num3 = roundDouble(-12.3412, 2);
// -12.34
double num4 = roundDouble(-12.3456, 2);
// -12.35

To make decimal operations you can use the decimal package.
final d = Decimal.parse;
print(d('399.9') / d('100')); // => 3.999

Related

iOS Percentage Keeps Rounding [duplicate]

hi I have a big doubt of using floats for divisions,
here the test code::
- (void)chuza
{
float option1 = 0;
float option2 = 0;
option1 = 100/50;
option2 = 50/100;
NSLog(#"option1 :: %f",option1);
NSLog(#"option2 :: %f",option2);
}
So,
I get:
2012-10-19 16:21:45.405 Project[2023:14f03] option1 :: 2.000000
2012-10-19 16:21:45.405 Project[2023:14f03] option2 :: 0.000000
so my question is:
why would the float like when
denominator > numerator
but doesnt like
numerator > denominator ??
Thanks!
That looks a lot like integer division to me since you are dividing two integer numbers. When dividing two integers (in most if not all programming languages) ignores the remainder of the division.
Think of how that line is being evaluated. First the integer division is calculated and then the integer result is cast to a float to be stored in the float variable.
Note that integers don't store any decimals at all so even 0.999 as an integer would be 0. It's not a problem about rounding.
It's also not about the denominator being bigger than the numerator. Try dividing 100/30 and the result will be 3, not 3.33333.. as it would be for float division.
You can solve this by casting the numbers to floats or making sure they are float numbers.
Casting
option2 = ((float)50/(float)100);
Dividing floats
option2 = 50.0f/100.0f;
Neither 100 nor 50 are floats, they're integers. That means you're doing integer division and assigning the result to a floating point variable. Since integer division truncates (throws away fractional results), 50/100 yields 0. 100 is divisible by 50, which which is why you get the 2.000000 result. Try your program with 75 and 100, and you'll see there's more at work than just which direction the division goes.
It's treating your numbers as integers, performing the division and then putting the result into a float.
Try this option2 = 50.0f/100;

iOS UInt64 number to float error

UInt64 intValue = 999999900;
float tt = intValue;
NSLog(#"float tt = %f", tt);
the output result is "float tt = 999999872", as you can see the UInt64 convert to float lose something, the Max float is bigger than 999999900, so I think the value 999999900 can be cast to float, so my question is why lose 28 in iOS?
float has a limited amount of precision. It's not the size of the number, it's the number of significant digits (9 in this case).
Use double instead of float to get more precision.
UInt64 intValue = 999999900;
double tt = intValue;
NSLog(#"double tt = %f", tt);
Why are you using float and not double? Has nobody told you that float has very limited precision (around 7 digits) while double has about 15 digits?
As a rule, you should NEVER use float instead of double unless you yourself can give a reasonable explanation why float would be more suitable than double.
So your question is: Why do I lose precision when I intentionally throw away 8 digits and precision, and what can I do? The answer is very simple: You lost precision because you threw it away yourself. Use double instead of float.

Formatting an integer value

Im obtaining an int value from UITextField [self.dbRef.text intValue];
I want to then format that value so I can add a decimal place that precceds the number ie. If [self.dbRef.text intValue]; returns 4 i need that value to be 0.04
So far I have tried various ways including
float Y = ([self.dbRef.text intValue]/100);
slice.value = Y;
NSLog(#"float Y value = %f",Y);
returns zero
NSString* formatedTotalApplianceString = [NSString stringWithFormat:#"0.%#", self.dbRef.text];
NSLog(#"formated string = %#",formatedTotalApplianceString);
int totalAppliances = [formatedTotalApplianceString intValue];
NSLog(#"Resulting int value = %d",[formatedTotalApplianceString intValue]);
slice.value = totalAppliances;
NSLog(#"total appliances int value = %d",totalAppliances);
returns zero
You're doing an integer division, so the 0 value is correct in that context as integers cannot represent fractions (unless you're doing fixed point arithmetics, but that's a different can of worms). You need to do a floating point division, for example:
float Y = ([self.dbRef.text floatValue]/100.0f);
Either the [self.dbRef.text floatValue] or the 100.0f will turn this into a float division, because if the other side would be an int it would automatically get casted to a float. But the "best" way is to have both values of the same type.
Change
float Y = [self.dbRef.text intValue]/100;
to
float Y = ((float)[self.dbRef.text intValue])/100;
in your first variant.
Dividing int by int returns you int result even if then you assign it to float. 4/100 = 0 in such case.
The problem with [self.dbRef.text intValue]/100 is that it's an integer division. It drops the fraction. One way to work around it is to divide by 100.0:
[self.dbRef.text intValue]/100.0
However, this is not the most efficient way of doing it if all you need is adding a zero in front of a fraction: you could avoid float altogether by padding your printed int to two positions with leading zeros:
// If text is 4, the code below prints 0.04
NSLog(#"0.%02d", [self.dbRef.text intValue]);
The first code returns zero because you are performing an integer division, which produces an integer result. You should cast the value to a float.
The second code also returns zero because you're asking for the intValue of a floating point value. So the decimal part will be discarded.
NSString has also a floatValue method, you should use it to get a floating value. Once divided by 100 you will still have a floating point value (in a division if the quotient or the dividend is a float and the other an integer, the integer gets promoted to float):
float Y = ([self.dbRef.text floatValue]/100);
slice.value = Y;

Get a fraction from its decimal number

I am developing a program that solves a system of equations. When it gives me the results, it is like: "x1= 1,36842". I'd like to get the fraction of that "1,36842", so I wrote this code.
procedure TForm1.Button1Click(Sender: TObject);
var numero,s:string;
a,intpart,fracpart,frazfatta:double;
y,i,mcd,x,nume,denomin,R:integer;
begin
a:=StrToFloat(Edit1.Text); //get the value of a
IntPart := Trunc(a); // here I get the numerator and the denominator
FracPart := a-Trunc(a);
Edit2.Text:=FloatToStr(FracPart);
numero:='1';
for i:= 1 to (length(Edit2.Text)-2) do
begin
numero:=numero+'0';
end; //in this loop it creates a string that has many 0 as the length of the denominator
Edit3.text:=FloatToStr(IntPart);
y:=StrToInt(numero);
x:=StrToInt(Edit3.Text);
while y <> 0 do
begin
R:= x mod y;
x:=y;
y:=R;
end;
mcd:=x; //at the end of this loop I have the greatest common divisor
nume:= StrToInt(Edit3.Text) div mcd;
denomin:= StrToInt(numero) div mcd;
Memo1.Lines.Add('fraction: '+IntToStr(nume)+'/'+IntToStr(denomin));
end;
It doesn't work correctly because the fraction that it gives to me is wrong. Could anyone help me please?
Your code cannot work because you are using binary floating point. And binary floating point types cannot represent the decimal numbers that you are trying to represent. Representable binary floating point numbers are of the form s2e where s is the significand and e is the exponent. So, for example, you cannot represent 0.1 as a binary floating point value.
The most obvious solution is to perform the calculation using integer arithmetic. Don't call StrToFloat at all. Don't touch floating point arithmetic. Parse the input string yourself. Locate the decimal point. Use the number of digits that follow to work out the decimal scale. Strip off any leading or trailing zeros. And do the rest using integer arithmetic.
As an example, suppose the input is '2.79'. Convert that, by processing the text, into numerator and denominator variables
Numerator := 279;
Denominator := 100;
Obviously you'd have to code string parsing routines rather than use integer literals, but that is routine.
Finally, complete the problem by finding the gcd of these two integers.
The bottom line is that to represent and operate on decimal data you need a decimal algorithm. And that excludes binary floating point.
I recommend defining a function GreaterCommonDivisor function first (wiki reference)
This is going to be Java/C like code since I'm not familiar with Delphi
let
float x = inputnum // where inputnum is a float
// eg. x = 123.56
Then, multiplying
int n = 1;
while(decimalpart != 0){// or cast int and check if equal-> (int)x == x
x = x * 10;
decimalpart = x % 1;
// or a function getting the decimal part if the cast does work
n *= 10;
}
// running eg. x = 123.56 now x = 12356
// n = 100
Then you should have (float)x/n == inputnum at this point eg. (12356/100 == 123.56)
This mean you have a fraction that may not be simpified at this point. All you do now is implement and use the GCD function
int gcd = GreaterCommonDivisor(x, n);
// GreaterCommonDivisor(12356, 100) returns 4
// therefore for correct implementation gcd = 4
x /= gcd; // 12356 / 4 = 3089
n /= gcd; // 100 / 4 = 25
This should be quick and simple to implement, but:
Major Pitfalls:
Float must be terminating. For example expected value for 0.333333333333333333 won't be rounded to 1/3
Float * n <= max_int_value, otherwise there will be a overflow, there are work around this, but there may be another solutions more fitting to these larger numbers
Continued fractions can be used to find good rational approximations to real numbers. Here's an implementation in JavaScript, I'm sure it's trivial to port to Delphi:
function float2rat(x) {
var tolerance = 1.0E-6;
var h1=1; var h2=0;
var k1=0; var k2=1;
var b = x;
do {
var a = Math.floor(b);
var aux = h1; h1 = a*h1+h2; h2 = aux;
aux = k1; k1 = a*k1+k2; k2 = aux;
b = 1/(b-a);
} while (Math.abs(x-h1/k1) > x*tolerance);
return h1+"/"+k1;
}
For example, 1.36842 is converted into 26/19.
You can find a live demo and more information about this algorithm on my blog.
#Joni
I tried 1/2 and the result was a "division by zero" error;
I correct the loop adding:
if b - a = 0 then BREAK;
To avoid
b:= 1 / (b - a);

Truncating Actionscript Number

I have a number in actionscript, arrived at via some arbitrary math:
var value:Number = 45 * (1 - (1 /3));
trace(value);//30.00000000004
Now, I would like to take the ceiling of this number, except in cases where the amount it is greater than the next lower integer is smaller than some epsilon. In the above example, I really want to round to 30, but only in the case where I know I'm getting a rounding error:
Math.ceil(value); //I want 30, but get 31
Math.ceil(30.1); //In this case, it's reasonable to get 31
Is there an elegant way to truncate a Number in actionscript? Or easily discard any part of the number that is less than some epsilon?
Is this method is of any help to you?
var precision:int = 4;
var isActualCeilingValRequred:Boolean;
var thresholdValForCeiling:int = 100;
private function getCeilingValue(num:Number):Number
{
var tempNum = num * Math.pow(10, precision);
var decimalVal = tempNum % Math.pow(10, precision);
if(decimalVal < thresholdValForCeiling) {
return Math.floor(num);
} else {
return Math.Ceil(num);
}
}
var value:Number = 45 * (1 - (1 /3));
trace(value);//30.00000000004
// Play with arbitraryPrecision until you are satisfied with
// the accuracy of your results
var arbitraryPrecision:int = 3;
var fixed:Number = value.toFixed(arbitraryPrecision);
trace(Math.ceil(fixed));
The basic way to round a number to a specified number of fractional digits is to multiply the number to 10^DIGITS to shift the decimal point DIGITS digits to the left, perform the rounding, and divide by the same 10^DIGITS to shift the decimal point back to the right.
var value:Number = 45 * (1 - (1 / 3));
trace(value); // 30.000000000000004
trace(Math.ceil(value)); // 31
// Round the number to 13 decimal digits.
const POWER:Number = 1e13;
value = Math.round(value * POWER) / POWER;
trace(value); // 30
// Compute number's ceiling.
value = Math.ceil(value);
trace(value); // 30`
It works for your example, but there's a big gotcha. If you change your value to be 450 * (1 - (1 / 3));, your original problem will appear again. Now to get rid of it, you would have to round to 12 decimal digits. Basically, the significand of a double-precision format (Number) can hold about 15 significant digits. This means as the value increases by a factor of ten, the decimal points moves to the left and that last "4" digit you want to get rid of becomes closer and closer to the decimal point. So the code becomes more complicated.
var value:Number = 450 * (1 - (1 / 3));
trace(value); // 30.000000000000004
trace(Math.ceil(value)); // 31
var exp:Number = Math.floor(Math.log(Math.abs(value)) * Math.LOG10E);
trace('exp=' + exp); // exp=2
const POWER:Number = Math.pow(10, 14 - exp);
value *= POWER;
trace(value); // 300000000000000.06
value = Math.round(value);
trace(value); // 300000000000000
value /= POWER;
trace(value); // 300
As you can see, it now works regardless of the value's magnitude.
First, I find the number's exponent by taking a base-10 logarithm of the number's absolute value, then rounding it down. If you calculate a = value * Math.pow(10, exp);, then value could be represented as a * 10^b, where (1 ≤ |a| < 10), known as normalized scientific notation. But that's not what we're doing here. Now that we know how many digits are on the left of the decimal point, we will shift the decimal point right, but not too far, to keep one 0 and this error digit we want to get rid of, on the right side of the decimal point. So, multiply by 10^(14-exp), round, then divide by the same power.

Resources