let xCoordinate: CGFloat = 1.4
XCTAssertEqual(view.frame.origin.x, xCoordinate)
I got the following error while running a test, as shown in the screenshot:
XCTAssertEqual failed: ("1.4") is not equal to ("1.4") -
Does anyone have any solutions or explanations?
If I am not making mistake take a look at this option of the evaluation of the CGFloat:
XCTAssertEqual(_, _, accuracy:)
In this case you could set accuracy to evaluate CGFloat numbers because evaluation of them without take in to account accuracy is not right.
Does anyone have any solutions or explanations?
The solution is what Oleg has suggested. The explanation is that 1.4 is not expressible as a CGFloat. In normal decimals, you may have noticed that, unless the denominator of a fraction is only divisible by 2 or 5 (the factors of 10) when you try ti convert it to a decimal number, it goes on forever. eg. 1/3 is 0.33333333333...
The same applies to CGFloats except the number base is 2, not 10. 1.4 is 7/5. 5 is not divisible by 2, therefore if converted to a binary number, it would repeat forever. In fact, it would be 1.0110011...
So your view.frame.origin.x is likely to be a number close to 1.4 but not exactly 1.4 and your xCoordinate will be a different number very close to 1.4. These two numbers do not compare equal, but when rounded to say six decimal places to be printed, look like 1.4.
Related
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
I have one simple question..
I have this code:
program wtf;
var i:integer;
begin
for i:=1 to 20 do
if sqrt(i)*sqrt(i)<>i then writeln(i);
readln
end.
...
it goes through the loop 20 times and for numbers from 1 to 20 and it checks if square root multiplied buy square root of same number is equal to that number.
If we use mathematical rules this program should never have anything on output but ....
I get this :
2
3
5
6
7
8
10
12
13
15
18
19
20
can sombody explain what is going on?
This is because of precision. The square root of a number that is not a perfect square will give an irrational number, which cannot be represented in memory properly using floating-point arithmetic.
Instead, the number gets truncated after some digits (in binary, but the concept is the same as in decimal).
The number is now very close to, but not quite, the square root of the original number. Squaring it will produce a number that is very close to the original, but not quite.
Imagine it like this, the square root of 2 is 1.4142135623........(etc.) but it gets cut off to 1.414213 for memory reasons. 1.414213 * 1.414213 = 1.99999840937 and not 2.
However, the square root of 4 is 2, and this can be stored in memory fully, without being cut off after a few decimal places. When you then do 2 * 2 you do get exactly 4.
Sometimes the number might get cut off, but when squaring it is still close enough to produce the original value. This is why 11 does not show.
sqrt generates floating point numbers. When using floats, on a computer, you cannot compare values and expect absolute equality. You must use a threshold difference comparison. floats are not used to count things, they are used to measure things, (to count things, use integers),. No two measured (even in the real world) values are ever exactly the same. they are only "close enough".
On a computer, it is impossible to represent every possible real number. SO every calculated value gets represented by the "closest" number in the set of possible numbers, (for that data type), that can be represented on the computer. This means that it is very slightly incorrect, and therefore after a few calculations, it will not conform to perfect equality comparisons.
I wanted to implement a simple parser for double values (just for fun). However, I noticed that when handling the decimal shift, I get rounding errors when multiplying the value with powers of 10.
I'm wondering how double.Parse ensures that the result value is as close to the string value as possible?
Just an example:
When parsing 0.0124 (=124*0.0001), I get 0.012400000000000001. However, double.Parse displays 0.0124 as expected.
The solution seems quite simple:
Just don't multiply by values smaller than 1 (e.g. 0.0001 in the above example) but divide by 1/x (10000 in the above example).
I think the reason is simply that integer values have an exact representation (up to 2^53), so there is no rounding error in the quotient (as there was in the factor < 1).
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 8 years ago.
I am reading from a txt file and populating a core data entity.
At some point I have read the value form the TXT file and the value is #"0.9".
Now I assign it to a CGFloat.
CGFloat value = (CGFloat)[stringValue floatValue];
debugger shows value as 0.89999997615814208 !!!!!!?????
why? bug? Even if it things [stringValue floatValue] is a double, casting it to CGFloat should not produce that abnormality.
The binary floating point representation used for float can't store the value exactly. So it uses the closest representable value.
It's similar to decimal numbers: It's impossible to represent one third in decimal (instead we use an approximate representation like 0.3333333).
Because to store a float in binary you can only approximate it by summing up fractions like 1/2, 1/4, 1/8 etc. For 0.9 (any many other values) there is no exact representation that can be constructed from summing fractions like this. Whereas if the value was say, 0.25 you could represent that exactly as 1/4.
Floating point imprecision, check out http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Basically has to do with how floating points work, they don't just store a number, they store a math problem. Broken down by a base number, and a precision. It then must combine the two numbers via math operation to retrieve the actual value, which doesn't always turn out to be exactly what you assigned to it.
Good morning all,
I'm having some issues with floating point math, and have gotten totally lost in ".to_f"'s, "*100"'s and ".0"'s!
I was hoping someone could help me with my specific problem, and also explain exactly why their solution works so that I understand this for next time.
My program needs to do two things:
Sum a list of decimals, determine if they sum to exactly 1.0
Determine a difference between 1.0 and a sum of numbers - set the value of a variable to the exact difference to make the sum equal 1.0.
For example:
[0.28, 0.55, 0.17] -> should sum to 1.0, however I keep getting 1.xxxxxx. I am implementing the sum in the following fashion:
sum = array.inject(0.0){|sum,x| sum+ (x*100)} / 100
The reason I need this functionality is that I'm reading in a set of decimals that come from excel. They are not 100% precise (they are lacking some decimal points) so the sum usually comes out of 0.999999xxxxx or 1.000xxxxx. For example, I will get values like the following:
0.568887955,0.070564759,0.360547286
To fix this, I am ok taking the sum of the first n-1 numbers, and then changing the final number slightly so that all of the numbers together sum to 1.0 (must meet validation using the equation above, or whatever I end up with). I'm currently implementing this as follows:
sum = 0.0
array.each do |item|
sum += item * 100.0
end
array[i] = (100 - sum.round)/100.0
I know I could do this with inject, but was trying to play with it to see what works. I think this is generally working (from inspecting the output), but it doesn't always meet the validation sum above. So if need be I can adjust this one as well. Note that I only need two decimal precision in these numbers - i.e. 0.56 not 0.5623225. I can either round them down at time of presentation, or during this calculation... It doesn't matter to me.
Thank you VERY MUCH for your help!
If accuracy is important to you, you should not be using floating point values, which, by definition, are not accurate. Ruby has some precision data types for doing arithmetic where accuracy is important. They are, off the top of my head, BigDecimal, Rational and Complex, depending on what you actually need to calculate.
It seems that in your case, what you're looking for is BigDecimal, which is basically a number with a fixed number of digits, of which there are a fixed number of digits after the decimal point (in contrast to a floating point, which has an arbitrary number of digits after the decimal point).
When you read from Excel and deliberately cast those strings like "0.9987" to floating points, you're immediately losing the accurate value that is contained in the string.
require "bigdecimal"
BigDecimal("0.9987")
That value is precise. It is 0.9987. Not 0.998732109, or anything close to it, but 0.9987. You may use all the usual arithmetic operations on it. Provided you don't mix floating points into the arithmetic operations, the return values will remain precise.
If your array contains the raw strings you got from Excel (i.e. you haven't #to_f'd them), then this will give you a BigDecimal that is the difference between the sum of them and 1.
1 - array.map{|v| BigDecimal(v)}.reduce(:+)
Either:
continue using floats and round(2) your totals: 12.341.round(2) # => 12.34
use integers (i.e. cents instead of dollars)
use BigDecimal and you won't need to round after summing them, as long as you start with BigDecimal with only two decimals.
I think that algorithms have a great deal more to do with accuracy and precision than a choice of IEEE floating point over another representation.
People used to do some fine calculations while still dealing with accuracy and precision issues. They'd do it by managing the algorithms they'd use and understanding how to represent functions more deeply. I think that you might be making a mistake by throwing aside that better understanding and assuming that another representation is the solution.
For example, no polynomial representation of a function will deal with an asymptote or singularity properly.
Don't discard floating point so quickly. I could be that being smarter about the way you use them will do just fine.
I'm trying to implement decimal arithmetic in (La)TeX. I'm trying to use dimens to store the values. I want the arithmetic to be exact to some (fixed) number of decimal places. If I use 1pt as my base unit, then this fails, because \divide rounds down, so 1pt / 10 gives 0.09999pt. If I use something like 1000sp as my base unit, then I get working fixed point arithmetic with 3 decimal places, but I can't figure out an easy way to format the numbers. If I try to convert them to pt, so I can use TeX's display mechanism, I have the same problem with \divide.
How do I fix this problem, or work around it?
The fp package provides fixed point arithmetic for LaTeX. The LaTeX3 Project are currently implementing something similar as part of the expl3 bundle. The code is currently not on CTAN, but can be grabbed from the SVN (or will appear when the next update from the SVN to CTAN takes place).
I would represent all the values as integers and scale them appropriately. For example, when you need three decimal digits, 0.124 would be represented as 124. This is nice because addition and subtraction are trivial. When multiplying two numbers a and b, you would have to divide the result by 1000 to get the proper representation. Dividing works by multiplying the result with 1000.
You still have to get the rounding issues correct, but this isn't very difficult. At least if you don't get near the maximum representable integer (I don't remember if it's 2^31-1 or 2^30-1).
Here is some code:
\def\fixadd#1#2#3{%
#1=#2\relax
\advance #1 by #3\relax
}
\def\fixsub#1#2#3{%
#1=#2\relax
#1=-#1\relax
\advance #1 by #3\relax
#1=-#1\relax
}
\def\fixmul#1#2#3{%
#1=#2\relax
\multiply #1 by #3\relax
\divide #1 by 1000\relax
}
\def\fixdiv#1#2#3{%
#1=#2\relax
\divide #1 by #3\relax
\multiply #1 by 1000\relax
}
\newcount\numa
\newcount\numb
\newcount\numc
\numa=1414
\numb=2828
\fixmul\numc\numa\numb
\the\numc
\bye
The operations are modeled after a three register machine, where the first is the destination and the other two are the operands. The rounding after the multiplication and division, including corner cases for very large or very small numbers are left as an exercise to you.