# Upping numerical precision

**URL:** <https://www.ruby-forum.com/t/upping-numerical-precision/163018>\
**Category:** Ruby\
**Created:** [March 16, 2009, 7:01pm UTC](https://www.ruby-forum.com/t/upping-numerical-precision/163018 "2009-03-16T19:01:02Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 16, 2009, 7:01pm UTC](https://www.ruby-forum.com/t/upping-numerical-precision/163018/1 "2009-03-16T19:01:02Z")

</div>

Hey All,

I got me this fancy method for classifying documents that basically  
does this at one point:

p = 1  
words.each do |w|  
p \*= calc\_prob(w)  
end  
chi = -2.0 \* Math.log§

I’m finding that p is often going to 0.0 b/c the numbers returned by  
calc\_prob are sometimes outlandishly small (or there are just so many  
words in the doc that the loop runs long enough to zero out the  
variable p). This causes problems for the call to Math.log of course  
(e.g., Errno::EDOM).

I have tried two things. First, after some desperate flailing on  
google I added:

require ‘rational’  
require ‘mathn’

to my script and hoped that ruby would read my mind WRT using  
rationals where possible & that rationals would extend the reach of  
ruby’s arithmetic into the too-outlandishly-small-for-floats range.

When that did not seem to avail me, I put this in my words.do loop:

if p == 0.0 then  
p = Float::MIN  
end

That works, but makes me wonder if there’s a smarter thing to do w/  
those rational and mathn libs to really get the effect I hoped for  
just from including them in my script.

Is there?

Many thanks!

-Roy

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 16, 2009, 10:08pm UTC](https://www.ruby-forum.com/t/upping-numerical-precision/163018/2 "2009-03-16T22:08:30Z")

</div>

removed\_email\_address@domain.invalid wrote:

> Hey All,  
> (…)  
> chi = -2.0 \* Math.log§
> 
> I’m finding that p is often going to 0.0 b/c the numbers returned by  
> calc\_prob are sometimes outlandishly small  
> (…)  
> That works, but makes me wonder if there’s a smarter thing to do w/  
> those rational and mathn libs to really get the effect I hoped for  
> just from including them in my script.
> 
> Is there?
> 
> Many thanks!
> 
> -Roy

Are you sure you required ‘mathn’ before defining your calc\_prob method?

big = 10\*\*100

small = 1/big  
p small.zero? # true

require ‘mathn’  
small = 1/big  
p small.zero? # false  
p small.class # Rational

p -2.0\*Math.log(small)

hth,

Siep

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 17, 2009, 4:01am UTC](https://www.ruby-forum.com/t/upping-numerical-precision/163018/3 "2009-03-17T04:01:17Z")

</div>

On Mar 16, 2:06 pm, Siep K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > just from including them in my script.
> 
> hth,
> 
> Siep

Thanks for the response! I think the issue may be that I’m not doing  
any division–just multiplication. Check it out:

irb(main):001:0\> require ‘mathn’  
=\> true  
irb(main):002:0\> x = 0.5  
=\> 0.5  
irb(main):003:0\> 1000.times do  
irb(main):004:1\* x \*= x  
irb(main):005:1\> end  
=\> 1000  
irb(main):006:0\> x  
=\> 0.0  
irb(main):007:0\> x.class  
=\> Float  
irb(main):008:0\>

But the more I think about it, the more I think I’m fussing over  
nothing (ha ha!). I think if my p var goes to zero, I should just set  
it = Float::MIN & break out of that loop. My calc\_prob method will  
only ever return values \<= 1, so there’s no sense in letting it  
continue to spin down the value of p (if you can tell what I’m trying  
to say).

Thanks!

-Roy

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 17, 2009, 7:15pm UTC](https://www.ruby-forum.com/t/upping-numerical-precision/163018/4 "2009-03-17T19:15:33Z")

</div>

On Mar 16, 10:56 pm, Roy P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> irb(main):005:1\> end  
> only ever return values \<= 1, so there’s no sense in letting it  
> continue to spin down the value of p (if you can tell what I’m trying  
> to say).
> 
> Thanks!
> 
> -Roy

Roy,

It all depends on how much range of data you want. If you need more  
granularity at the tiny end, you can always re-normalize… just  
initialize p to be 1e6 or something, rather than 1. Then after the log  
you can just subtract the constant exponent to get back to your  
original range.

-t3ch.dude

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 17, 2009, 11:42pm UTC](https://www.ruby-forum.com/t/upping-numerical-precision/163018/5 "2009-03-17T23:42:41Z")

</div>

I don’t think you need more precision. Basic math can help you here:  
log(a\*b) = log(a) + log(b)

so

logp=0  
words.each do |w|  
logp += Math.log( calc\_prob(w) )  
end  
chi = -2.0 \* logp
