Removing scientific notation from float - ruby

I'm currently multiplying two floats like so: 0.0004 * 0.0000000000012 = 4.8e-16
How do I get the result in a normal format, i.e. without the scientific notation, something like 0.0000000000324 and then round it up to say 5 numbers.

You can use string formatting.
a = 0.0004 * 0.0000000000012 # => 4.8e-16
'%.5f' % a # => "0.00000"
pi = Math::PI # => 3.141592653589793
'%.5f' % pi # => "3.14159"

Related

Add percentage to number in Ruby

How can I add a percentage to a number in Ruby?
In this example I want to add 20% to 32.92:
irb(main):001:0> 32.92 * (1 + (20 / 100))
=> 32.92
Google answers with the correct answer; 39.50.
Lets say your base_value is: 39.92.
Your markup is 20.
Integer division will lead to the following:
20 / 100
# => 0
So irb is the right direction. This gives better results:
20.to_f / 100
# => 0.2
So the final calculation will look like this:
final_value = (base_value + (markup.to_f / 100) * base_value).round
This gives you the expected value.
As you don’t mind the result to be floored instead of rounded it’s possible to get correct result using integer division:
final_value = base_value + base_value * markup / 100
20 / 100 returns 0, because it's integer division if you pass integers as arguments. Instead, you can pass floats, like this:
32.92 * (1 + (20.0 / 100.0))
or do simply:
32.92 * 1.2

How can I generate random numbers whose average follows a sine wave in Ruby?

I'm not a math guy, so I don't really know what I'm trying to do is called, but I'm sure there's a name for it. ;-)
I'm wanting to generate an array of random numbers in Ruby whose average at each element in the array follows a sine wave. What I mean by average at each element is the average at element n would be ary[0..n].inject(:+).to_f / (n + 1). So, if I loop from 0..n over the array of random numbers and generate the average like I described, I'd like the resulting values to follow a sine wave. I just don't know how to actually generate the random numbers in such a way...
# assuming `ary` is the array of random numbers
# I'm trying to figure out how to generate...
averages = []
(0..ary.size).each do |n|
averages << ary[0..n].inject(:+).to_f / (n + 1)
end
# `averages` should plot as a sine wave now...
Here's an idea. Create a class that has some sample size over which it generates points in a sine wave plus some random "fudge factor" (variance) above or below that point. This way, if you plot the number of points in the sample size you should see a sine wave with "roughness" according to the configured variance (fudge factor).
class RandomSineWave
attr_reader :size
def initialize(size=20, variance=0.2)
#size = size
#step = 2 * Math::PI / size
#position = 0
#variance = variance
end
def next
#position = 0 if #position >= 2 * Math::PI
next_rand = Math.sin(#position) + (rand * #variance) - (#variance / 2)
#position += #step
next_rand
end
end
# Generate TSV output for demonstration.
rsw = RandomSineWave.new
rsw.size.times { |i| puts [i, rsw.next].join "\t" }
You can fiddle with the "roughness" by modifying the second argument to the constructor:
rsw = RandomSineWave.new(20, 0.8) # Results plotted below...
As I understand, given some positive integer n, you want to construct an array of n probability distributions such that the expected values of partial sums of random variables describes a sine wave. I presume the sine wave is over the interval (0..2*π) and that the expected values are to be evenly spaced over that interval.
We must first ask if these probability distributions are statistically independent. If they are not, it becomes hopelessly complex, so I will assume they are independent. Whether they are identical distributions, after adjusting for differences in their means, is not necessary or even important. I'll come back to that later.
Since you want the expected values of partial sums of the random variables Xi to describe a sine wave, we require that:
E [∑j=0...iXj] = k * sin(2*π*i/n)
for all i = 0...n-1, for a given scale factor, k (with (E[..] denoting "expected value"). We can assume, without loss of generality, that k=1, as we can always scale the random variables by k, resulting in their means being scaled by the same constant.
Because the distributions are independent, we can write:
∑j=0...imj = sin(2*π*i/n)
where
mi = E[Xi] is Xi's mean.
In Ruby-speak, for an array x of n values (floats), this is:
x[0,i].reduce(:+) = Math::sin(2.0 * Math::PI * i.to_f/n)
We can easily compute x. Assume n = 36.
For i = 0:
x[0,0].reduce(:+) = Math::sin(2.0 * Math::PI * 0.0/36)
# x[0] = 0
Let:
s = x[0]
#=> 0.0
For i = 1:
x[0,1].reduce(:+) = Math::sin(2.0 * Math::PI * 1.0/36).round(6)
#=> 0.0 + x[1] = Math::sin(0.17453292519943295).round(6)
#=> = 0.173648
So
x[1] = 0.173648 - 0.0
#=> 0.173648
Now let
s += x[1]
#=> 0.173648
For i = 2:
x[0,2].reduce(:+) = Math::sin(2.0 * Math::PI * 2.0/36).round(6)
#=> s + x[2] = Math::sin(0.3490658503988659).round(6)
#=> 0.173648 + x[2] = 0.342020
So
x[2] = 0.342020 - 0.173648
#=> 0.168372
We then update s:
s += 0.168372
#=> 0.173648 += 0.168372
#=> 0.342020
and then compute x[3] similarly, then each of the remaining x's:
def compute(n, p=6)
sum = 0.0
n.times.map do |i|
if i.zero?
[0.0, 0.0, 0.0, 0.0]
else
x = Math::sin(2.0 * Math::PI * i.to_f/n) - sum
sum += x
[(2.0*(i.to_f/n)*Math::PI).round(p), x.round(p),
sum.round(p), Math::sin(sum).round(p)]
end
end
end
compute(36)
# radians x sum sin(sum) degrees
# [[0.0, 0.0, 0.0, 0.0 ], 0
# [0.174533, 0.173648, 0.173648, 0.172777],
# ...
# [1.396263, 0.045115, 0.984808, 0.833166],
# [1.570796, 0.015192, 1.0, 0.841471], 90
# [1.745329, -0.015192, 0.984808, 0.833166],
# ...
# [2.967060, -0.168372, 0.173648, 0.172777],
# [3.141593, -0.173648, 0.0, 0.0 ], 180
# [3.316126, -0.173648, -0.173648, -0.172777],
# ...
# [4.537856, -0.045115, -0.984808, -0.833166],
# [4.712389, -0.015192, -1.0, -0.841471], 270
# [4.886922, 0.015192, -0.984808, -0.833166],
# ...
# [5.934119, 0.15798, -0.34202, -0.335391],
# [6.108652, 0.168372, -0.173648, -0.172777]] 350
I will add a plot of these values when I have time to familiarize myself with #maeric's nifty plotting tool.
Now that we have the means, we can consider constructing probability distributions having those means.
Suppose, for example, we assume each random variable has the same uniform distribution with range (max-min) of rng, for varying means. If the mean were, say, 0.325467, we could generate a pseudo random-variate as follows:
rng * (rand-0.325467)
where
(0.5-0.174533).round(6)
#=> 0.325467
We therefore can generate pseudo-random variates for a uniform distribution with a given range and mean as follows:
def uniform_rv(rng, mean)
rng.to_f * (rand -0.5 -mean)
end

Internal rounding woes: accurate way to sum Ruby floating point numbers?

This is of course broken:
(0.1 + 0.1 + 0.1) => 0.30000000000000004
(0.1 + 0.1 + 0.1) == 0.3 # false
I don't need a perfect sum, just good enough to say two Floats are the same value. The best I can figure out is to multiply both sides of the equation and round. Is this the best way?
((0.1 + 0.1 + 0.1) * 1000).round == (0.3 * 1000).round
UPDATE: I'm stuck on Ruby v1.8.7.
There is a difference between summing accurately and comparing effectively. You say you want the former, but it looks like you want the later. The underlying Ruby float arithmetic is IEEE and has sensible semantics for minimizing accumulated error, but there always will be when using a representation that can't exactly represent all values. To accurately model error, FP addition shouldn't produce an exact value, it should produce an interval and further additions will operate on intervals.
In practice, many applications don't need to have detailed accounting for error, they just need to do their calculation and be aware that comparisons aren't exact and output decimal representations should be rounded.
Here's a simple extension to Float that will help you out with comparison. It or something like it should be in the stdlib, but ain't.
class Float
def near_enough?(other, epsilon = 1e-6)
(self - other.to_f).abs < epsilon.to_f
end
end
pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3)
=> true
pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3, 1e-17)
=> false
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5, 1e-5)
=> true
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5)
=> false
Picking an appropriate epsilon can be tricky in the general case. You should read What Every Computer Scientist Should Know About Floating-Point Arithmetic. I've found Bruce Dawson's floating point tricks blogs excellent, here's his chapter on Comparing Floating Point Numbers
If you really are concerned about accuracy, you could do your arithmetic using an exact representation. Ruby supplies a Rational class (even back in 1.8) which let's you do exact arithmetic on fractions.
pry(main)> r=Rational(1,10)
=> (1/10)
pry(main)> (r + r + r) == Rational(3,10)
=> true
pry(main)> (r + r + r) == 0.3
=> true
pry(main)> r.to_f
=> 0.1
pry(main)> (r + r + r).to_f
=> 0.3
The round method supports the specification of decimal places to which to round: http://www.ruby-doc.org/core-1.9.3/Float.html#method-i-round
So
(0.1 + 0.1 + 0.1).round(1) == (0.3).round(1)
... ought to be good.

Rational numbers not behaving like fractions in algebra with Ruby

Can someone please explain this to me?
x = Rational(3/4) * 8
=> (0/1) # I Expected it to return 6
x.to_i
=> 0
Thanks.
You are creating a Rational number with 3/4 as the only argument. 3/4 is 0, so, your code is equivalent to
Rational(0) * 8
which obviously is 0.
Compare this to
Rational(3, 4) * 8
# => (6/1)
where you explicitly pass both the numerator and denominator.
If you prefer having slashes in the fractions, you may use strings as arguments:
x = Rational('3/4') * 8
or
x = ('3/4'.to_r) * 8

Issue with precision of Ruby math operations

Do you know how to fix the following issue with math precision?
p RUBY_VERSION # => "1.9.1"
p 0.1%1 # => 0.1
p 1.1%1 # => 0.1
p 90.0%1 # => 0.0
p 90.1%1 # => 0.0999999999999943
p 900.1%1 # => 0.100000000000023
p RUBY_VERSION # => "1.9.2"
p 0.1%1 # => 0.1
p 1.1%1 # => 0.10000000000000009
p 90.0%1 # => 0.0
p 90.1%1 # => 0.09999999999999432
p 900.1%1 # => 0.10000000000002274
Big Decimal
As the man said;
Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation.
I have however had great success using the BigDecimal class. To quote its intro
Ruby provides built-in support for arbitrary precision integer arithmetic. For example:
42**13 -> 1265437718438866624512
BigDecimal provides similar support for very large or very accurate floating point numbers.
Taking one of your examples;
>> x = BigDecimal.new('900.1')
=> #<BigDecimal:101113be8,'0.9001E3',8(8)>
>> x % 1
=> #<BigDecimal:10110b498,'0.1E0',4(16)>
>> y = x % 1
=> #<BigDecimal:101104760,'0.1E0',4(16)>
>> y.to_s
=> "0.1E0"
>> y.to_f
=> 0.1
As you can see, ensuring decent precision is possible but it requires a little bit of effort.
This is true of all computer languages, not just Ruby. It's a feature of representing floating point numbers on binary computers:
What Every Computer Scientist Should Know About Floating Point Arithmetic
Writing 0.1 into a floating point will always result in rounding errors. If you want 'precise' decimal representation, you should use the Decimal type.

Resources