This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
So.. I'm trying to refactor a piece of code, namely:
v = [0.0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.0]
By using the .step method. Tried this but it's giving me some odd decimals for some of the numbers. Trying to figure out why this is?
0.0.step(by: 0.1, to: 1.0).to_a
Gives me this result:
=> [0.0,
0.1,
0.2,
0.30000000000000004,
0.4,
0.5,
0.6000000000000001,
0.7000000000000001,
0.8,
0.9,
1.0]
Ruby version: 2.3.0p0
How can I go about figuring out why this is happening? Each of those numbers returns a float.
Floats are inexact. Calculations (like adding) are more exact using Rationals. If you must use floats, convert to Floats after the calculations.
p 0.step(1, 1/10r).map(&:to_f) 3 =>[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
Related
Here is the problem, i need to run a function for each percentage possibility (2 floating points). So for that, i need an algorithm that identify each case for n elements.
For example:
An array of 2 elements would have the following distribution:
[1.00, 0.00]
[0.99, 0.01]
[0.98, 0.02]
[0.97, 0.03]
[...]
But in cases of more elements, this is more complexity:
[1.00, 0.00, 0.00, 0.00]
[0.99, 0.01, 0.00, 0.00]
[0.99, 0.00, 0.01, 0.00]
[0.99, 0.00, 0.00, 0.01]
[0.98, 0.02, 0.00, 0.00]
[0.98, 0.01, 0.01, 0.00]
[0.98, 0.01, 0.00, 0.01]
[0.98, 0.00, 0.02, 0.00]
[0.98, 0.00, 0.01, 0.01]
[0.98, 0.00, 0.00, 0.02]
[0.97, 0.03, 0.00, 0.00]
[0.97, 0.02, 0.01, 0.00]
[0.97, 0.02, 0.00, 0.01]
[0.97, 0.01, 0.02, 0.00]
[0.97, 0.01, 0.00, 0.02]
[0.97, 0.01, 0.01, 0.01]
[0.97, 0.00, 0.03, 0.00]
[0.97, 0.00, 0.00, 0.03]
[0.97, 0.00, 0.02, 0.01]
[0.97, 0.00, 0.01, 0.02]
[...]
Does anyone know a way to find these cases for n elements?
Its not necessary to save the array in memory, i just run a function or a part of code for each one of these cases.
This code/function could be just a print of the case.
I accept any language for response, thanks for your attention.
[Edit 1] The solution that i created with the help of Alejandro was that:
import numpy as np
n=4
f = open("possibilities.txt", "w")
def getPossibilities(array):
if array == None:
array = []
alreadySummed = sum(array)
remaining = round(1 - alreadySummed, 2)
if(len(array) == n-1):
newArr = [*array, remaining]
f.write(str(newArr) + "\n")
return
allRemainingPossibilities = np.arange(0, remaining + 0.01, 0.01)
for possibility in allRemainingPossibilities:
newArr = [*array, round(possibility, 2)]
getPossibilities(newArr)
getPossibilities(None)
f.close()
Basically, for each initial possibility, the code search for the remaining possibilities. And in cascade, show me all the possibilities
A mix of itertools and filter might do the work, I don't know how slow it could get with bigger n. Try something like this:
import numpy as np
from itertools import product
n=2
percentages = list(np.arange(0,1,0.01))
result = filter(lambda e: sum(list(e))==1, product(percentages, repeat=n))
for row in result:
print(row)
Given the following float values :
n00.0, n0.0, n.0, 0.n, 0.0n, 0.00n, 0.000n
where n can be 1, 2 or 5, what is the smartest and fastest way to extract the corresponding integer values, to be used as rounding parameters
-2, -1, 0, 1, 2, 3, 4
At the moment, I am using a hash table : fast, but not so smart, I think!
I thought using a hash was a good approach and was skeptical that it would be outperformed by -Math.log10(k).floor, so I ran the following benchmark.
Construct the hash
h = { 100.0=>-2, 10.0=>-1, 1.0=>0, 0.1=>1, 0.01=>2,
200.0=>-2, 20.0=>-1, 2.0=>0, 0.2=>1, 0.02=>2,
500.0=>-2, 50.0=>-1, 5.0=>0, 0.5=>1, 0.05=>2 }
Construct test array for benchmark (15 million elements)
n = 1_000_000
(arr = h.keys.flat_map { |k| [k]*n }.shuffle).size
#=> 15_000_000
arr.first(10)
#=> [20.0, 0.02, 5.0, 0.5, 0.02, 0.05, 500.0, 50.0, 50.0, 20.0]
arr.last(10)
#=> [500.0, 0.5, 0.1, 20.0, 0.01, 0.1, 500.0, 50.0, 0.05, 0.5]
Perform benchmark
require 'fruity'
compare(
hash: -> { arr.each { |k| h[k] } },
log10: -> { arr.each { |k| -Math.log10(k).floor } }
)
Running each test once. Test will take about 42 seconds.
hash is faster than log10 by 60.0% ± 10.0%
Let's say now I have an array that used to describe the shape of a polygon:
[
[0.0, 1.0],
[0.5, 1.0],
[0.5, 0.3],
[1.0, 0.3],
[1.0, 0.0],
[0.0, 0.0]
]
As shown on diagram above, the blue line(s) or vector points list is the result I was looking for.
Assuming the polygon only composed of one or more rectangular shapes, is there any way to extract/simplify the polygon to one or more lines?
I'm doing a bit 'o matrix algebra in ruby. When testing the results, I'm seeing what I can only assume is a rounding error.
All I'm doing is multiplying 3 matrices, but the values are fairly small:
c_xy:
[0.9702957262759965, 0.012661213742314235, -0.24159035004964077]
[0, 0.9986295347545738, 0.05233595624294383]
[0.24192189559966773, -0.050781354673095955, 0.9689659697053497]
i2k = Matrix[[8.1144E-06, 0.0, 0.0],
[0.0, 8.1144E-06, 0.0],
[0.0, 0.0, 8.1144E-06]]
c_yx:
[0.9702957262759965, 0, 0.24192189559966773]
[0.012661213742314235, 0.9986295347545738, -0.050781354673095955]
[-0.24159035004964077, 0.05233595624294383, 0.9689659697053497]
What I'm trying to do is c_xy * i2k * c_yx. Here's what I expect (this was done in Excel):
8.1144E-06 0 2.11758E-22
0 8.1144E-06 0
2.11758E-22 -5.29396E-23 8.1144E-06
And what I get:
[8.1144e-06, 1.3234889800848443e-23, 6.352747104407253e-22]
[0.0, 8.114399999999998e-06, -5.293955920339377e-23]
[2.117582368135751e-22, 0.0, 8.1144e-06]
As you can see, the first column matches, as does the diagonal. But then (in r,c indexing) (0,1) is wrong (though approaching 0), (0,2) is very wrong, and (1,2) and (2,1) seem to be transposed. I thought it had something to do with the8.1144e-6 value, and tried wrapping it in a BigDecimal to no avail.
Any ideas on places I can look? I'm using the standard Ruby Matrix library
edit
here's the code.
phi1 = 0.24434609527920614
phi2 = 0.05235987755982988
i2k = Matrix[[8.1144E-06, 0.0, 0.0],
[0.0, 8.1144E-06, 0.0],
[0.0, 0.0, 8.1144E-06]]
c_x = Matrix[[1, 0, 0],
[0, Math.cos(phi2), Math.sin(phi2)],
[0, -Math.sin(phi2), Math.cos(phi2)]]
c_y = Matrix[[Math.cos(phi1), 0, -Math.sin(phi1)],
[0, 1, 0],
[Math.sin(phi1), 0, Math.cos(phi1)]]
c_xy = c_y * c_x
c_yx = c_xy.transpose
c_xy * i2k * c_yx
i2k is equal to the identity matrix times 8.1144E-06. This simplifies the answer to:
c_xy * i2k * c_yx = 8.1144E-06 * c_xy * c_yx
However since c_yx = c_xy.transpose and c_xy is a rotation matrix, the transpose of any rotation matrix is its inverse. So c_xy * c_yx is the identity matrix, and thus the exact answer is 8.1144E-06 times the identity matrix.
Here is one way to calculate c_xy * c_yx without using the matrix algebra a priori:
require 'matrix'
require 'pp'
phi1 = 14 * Math::PI/180
phi2 = 3 * Math::PI/180
c_x = Matrix[
[1,0,0],
[0, Math.cos(phi2), Math.sin(phi2) ],
[0, -Math.sin(phi2), Math.cos(phi2) ] ]
c_y = Matrix[
[Math.cos(phi1), 0, -Math.sin(phi1) ],
[0,1,0],
[Math.sin(phi1), 0, Math.cos(phi1) ] ]
c_xy = c_y * c_x
c_yx = c_xy.transpose
product = c_xy * c_yx
pp *product
clone = *product
puts "\nApplying EPSILON:"
product.each_with_index do |e,i,j|
clone[i][j] = 0 if e.abs <= Float::EPSILON
end
pp clone
Output:
[1.0, 0.0, 2.7755575615628914e-17]
[0.0, 0.9999999999999999, -6.938893903907228e-18]
[2.7755575615628914e-17, -6.938893903907228e-18, 0.9999999999999999]
Applying EPSILON:
[1.0, 0, 0]
[0, 0.9999999999999999, 0]
[0, 0, 0.9999999999999999]
which one can then surmise should be the identity matrix. This uses Float::EPSILON which is about 2.220446049250313e-16 in order to set values that have an absolute value no more than this equal to 0. These kinds of approximations are inevitable in floating point calculations; one must evaluate the appropriateness of these approximations on a case-by-case basis.
An alternative is to do symbolic computation where possible rather than numeric.
Floating point numbers have a precision:
puts Float::DIG # => 15
That's the number of decimal digits a Float can have on my, and probably your system. Numbers smaller than 1E-15 can not be represented with a float. You could try BigDecimal for arbitrary large precision.
Just wondering how to sort an array of floats in Ruby, since "sort" and "sort!" only work for integer arrays.
Arrays of floats can certainly be sorted:
>> [6.2, 5.8, 1.1, 4.9, 13.4].sort
=> [1.1, 4.9, 5.8, 6.2, 13.4]
Maybe you have a nil in your array, which can't be sorted with anything.
You can sort a float array without any problem like :
irb(main):005:0> b = [2.0, 3.0, 1.0, 4.0]
=> [2.0, 3.0, 1.0, 4.0]
irb(main):006:0> b.sort
=> [1.0, 2.0, 3.0, 4.0]
perhaps you have something like this in your array and haven't noticed:
[1.0 , 3.0, 0/0, ...]
the 0/0 will give you a NaN which is impossible to compare with a Float... in this case you should try to
[2.3,nil,1].compact.sort
# => [1,2.3]
that or perhaps the same error with 1.0/0 wich yields infinity (but this error is detected by ruby)