Float Question

  • Thread starter Armando Padilla
  • Start date
A

Armando Padilla

This is probably the stupidest question ive ever had to ask on any board
so im sorry lol. :p

Yes i've googled and found a solution but i cant believe that the
solution presented is correct or that the great minds behind ruby did
not include something like this.

I want to get a float 2.3333 to display as 2.33 or 2.333 etc.

Now, i read the manual, Numerical, Float, Math sections but could not
find a way to do this. Yes you can use string manipulation but that
just defeats the purpose of having something like this built into the
Float stack.

ex. someFloat = Float.new(2) ==> 2.12
someFloat = Float.new(5) => 2.12345

Any thoughts?
 
C

Chris Cummer

What you're looking for is sprintf() though I suspect you know that
already from your comment below. Ie:

sprintf( "%0.02f", 234.2342342)

You deride this as "string manipulation" though in effect as soon as
you display the number that's what you're doing, no matter where or
why you want to display it. The number only exists as a true float as
long as you don't look at it; as soon as you do, you've forced it to
achieve stringness.

Makes sense?
 
A

Armando Padilla

Hey Chris thanks for the feedback. Yea im using that but i was looking
for something built into the Float stack. Something along the lines of
Float.new(<number of values after decimal here>). Basically something
without the need to use sprintf.

Next release of Ruby request? lol
 
P

Pat Maddox

Or even the current release!

class Float
def truncate(places = 0)
return to_i if places == 0
sprintf( "%0.#{places}f", self).to_f
end
end

irb(main):007:0> 234.2342342.truncate 2
=> 234.23
irb(main):008:0> 234.2342342.truncate
=> 234
 
H

HiddenBek

You can monkey patch Float to do this, basically. Whether or not it's
a good idea is another matter entirely.

class Float
def to_s
#force all Floats to 2 decimal places
"%.2f" % self
end
end

puts 1.2345678 # => 1.23

Or maybe:

class Float
attr_accessor :decimals
alias_method :default_to_s, :to_s
def to_s
decimals ? "%.#{decimals}f" % self : default_to_s
end
end

a = 1.234567
puts a # => 1.234567
a.decimals = 2
puts a # => 1.23
 
C

Chris Cummer

Hey Chris thanks for the feedback. Yea im using that but i was
looking for something built into the Float stack. Something along
the lines of Float.new(<number of values after decimal here>).
Basically something without the need to use sprintf.

In that case the monkey-patch suggestions made by others would do the
trick for you. I personally wouldn't like to see anything like this in
the Float class proper since it really isn't part of the float itself
but rather an operation on the string representation of it.

Of the m-p suggestions made (is this question now mp-complete?), I
like Pat Maddox's truncate() the best:
 
C

Chris Cummer

But it seems, few people know the star operator in printf format
strings. You can do this:

irb(main):021:0> module Precision
irb(main):022:1> def format(decimals,total=0)
irb(main):023:2> sprintf "%*.*f", total, decimals, self
irb(main):024:2> end
irb(main):025:1> end

You're right, I didn't know that one at all and it seems quite handy.
Thanks for the tip.
 
A

Armando Padilla

I fail to see where the issue with using (s)printf is.

If i use sprintf im assuming that the argument is changed to a string
type. If then i chose to calculate additional values with this string
type i would have to reconvert it to a float. On the surface its fine,
i wouldnt mind doing it but I need speed and any less lines that ruby
will translate too in terms of machine language is beneficial to me.

I actually like Maddox truncate example. Thanks Maddox. i wasnt aware
of both that feature and *.format <digit here> Klemme suggested.
 
U

Une Bévue

Armando Padilla said:
I actually like Maddox truncate example. Thanks Maddox. i wasnt aware
of both that feature and *.format <digit here> Klemme suggested.

I'm using that :

def aprox( eps = 1.0e-10 )
( self / eps ).round * eps
end


with :
a_float = 1.2345678901234567890
epss = [ 1.0e-10, 1.0e-8, 1.0e-6, 1.0e-4, 1.0e-2, 1.0, 1.0e2]
epss.each do | eps |
puts "#{a_float}.aprox( #{eps} ) -o-> #{a_float.aprox( eps )}"
end

gives :
1.23456789012346.aprox( 1.0e-10 ) -o-> 1.2345678901
1.23456789012346.aprox( 1.0e-08 ) -o-> 1.23456789
1.23456789012346.aprox( 1.0e-06 ) -o-> 1.234568
1.23456789012346.aprox( 0.0001 ) -o-> 1.2346
1.23456789012346.aprox( 0.01 ) -o-> 1.23
1.23456789012346.aprox( 1.0 ) -o-> 1.0
1.23456789012346.aprox( 100.0 ) -o-> 0.0

I'm also using an aproximate float comparator :
def ===( aFloat, eps = 1.0e-10)
begin
clazz = aFloat.class.to_s
raise "Argument \"#{aFloat}\" must be a Float (being of
#{clazz})." if clazz != "Float"
( self > aFloat - eps ) && ( self < aFloat + eps )
rescue
puts "An error occurred: #{$!}"
nil
end
end

with :
vref = 2.0
val = [ 2.00000000002, 2.00000002, 2.00002, 2.002 ]
val.each do | v |
puts "( #{vref} ===? #{v} ) = #{( vref === v )}"
puts "( #{vref} ===? #{v}, 1.0e-8 ) = #{( vref.===(v, 1.0e-8) )}"
puts "( #{vref} ===? #{v}, 1.0e-6 ) = #{( vref.===(v, 1.0e-6) )}"
puts "( #{vref} ===? #{v}, 1.0e-4 ) = #{( vref.===(v, 1.0e-4) )}"
end

gives :
( 2.0 ===? 2.00000000002 ) = true
( 2.0 ===? 2.00000000002, 1.0e-8 ) = true
( 2.0 ===? 2.00000000002, 1.0e-6 ) = true
( 2.0 ===? 2.00000000002, 1.0e-4 ) = true
( 2.0 ===? 2.00000002 ) = false
( 2.0 ===? 2.00000002, 1.0e-8 ) = false
( 2.0 ===? 2.00000002, 1.0e-6 ) = true
( 2.0 ===? 2.00000002, 1.0e-4 ) = true
( 2.0 ===? 2.00002 ) = false
( 2.0 ===? 2.00002, 1.0e-8 ) = false
( 2.0 ===? 2.00002, 1.0e-6 ) = false
( 2.0 ===? 2.00002, 1.0e-4 ) = true
( 2.0 ===? 2.002 ) = false
( 2.0 ===? 2.002, 1.0e-8 ) = false
( 2.0 ===? 2.002, 1.0e-6 ) = false
( 2.0 ===? 2.002, 1.0e-4 ) = false
 
G

Gary Wright

If i use sprintf im assuming that the argument is changed to a
string type. If then i chose to calculate additional values with
this string type i would have to reconvert it to a float. On the
surface its fine, i wouldnt mind doing it but I need speed and any
less lines that ruby will translate too in terms of machine
language is beneficial to me.


This statement just confused me more. sprintf doesn't change the
underlying objects--it just creates a string representation of them.
You are free to use the original objects as you like.

It sounds like you aren't primarily interested in the format of the
string representation of a float but instead would like to compute
a rounded or truncated value. That is a completely different
problem. Pat's solution included a roundtrip conversion to a
decimal/string representation, which is going to be inaccurate and
expensive. Of course if you want to 'round' a float then you'll
want to round to a power of two to avoid conversion problems.

Maybe BigDecimal objects would work better for you? You could
at least avoid the base2/base10 conversion problems.

Gary Wright
 
R

Robert Klemme

If i use sprintf im assuming that the argument is changed to a string
type. If then i chose to calculate additional values with this string
type i would have to reconvert it to a float.

But this is *exactly* what you asked for. Quoting from your original
posting:
I want to get a float 2.3333 to display as 2.33 or 2.333 etc.

You are clearly asking for a string representation with specific
properties, namely the number of digits after the decimal point.
On the surface its fine,
i wouldnt mind doing it but I need speed and any less lines that ruby
will translate too in terms of machine language is beneficial to me.

Maybe we should start over with you stating what it is that you want to do.

And please, do not top post.

Regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,271
Messages
2,571,361
Members
48,043
Latest member
BartEaster

Latest Threads

Top