ChatGPT解决这个技术问题 Extra ChatGPT

Why is division in Ruby returning an integer instead of decimal value?

For example:

9 / 5  #=> 1

but I expected 1.8. How can I get the correct decimal (non-integer) result? Why is it returning 1 at all?

Note that if you're actually using a method to return this value, you don't need to assign it to a variable; simply def method; a - b/8; end would return the result of the calculation from the method, as the last expression in a method call is the return value.

A
Andrew Marshall

It’s doing integer division. You can use to_f to force things into floating-point mode:

9.to_f / 5  #=> 1.8
9 / 5.to_f  #=> 1.8

This also works if your values are variables instead of literals. Converting one value to a float is sufficient to coerce the whole expression to floating point arithmetic.


This is the more "rails" answer than the accepted answer.
@muistooshort: i can't replicate it, sorry. I was probably doing something wrong.
@SeanRyan Why specifically Rails rather than Ruby in general? I don't see why a (Ruby on) Rails developer would do this specific thing any differently than a general Ruby developer. Perhaps I'm just nitpicking semantics and most people just see (Ruby on) Rails and Ruby as synonymous in cases like this.
Is there a way to ensure all math in a certain block is performed on floats (and where not float, coerced to float) without having to .to_f everything?
@stevec Sorry, I don't know of anything like that.
A
Andrew Marshall

It’s doing integer division. You can make one of the numbers a Float by adding .0:

9.0 / 5  #=> 1.8
9 / 5.0  #=> 1.8

This works but the to_f answer below seems more useful. Is to_f more idiomatic in Ruby?
The .to_f answer is better if you're dividing two variables that contain integers, e.g. a.to_f / b. If you're literally dividing two hard-coded integers (which is probably weird), then using 9.0 / 5 is fine.
Adding a decimal will make it a float, and when you do the division it will cast the integer to a float so that the result is a float. Integer division yields an integer answer. Using to_f on an integer is more explicit, whereas adding a decimal .0 to the integer is more implicit. I would recommend using to_f to be more explicit for anyone reading the code, although it may still not be clear what the intentions are to others.
K
Konrad Reiche

There is also the Numeric#fdiv method which you can use instead:

9.fdiv(5)  #=> 1.8

This is the fastest method I tested, the only way to get more performance is to divide operands that are floats to begin with. I've built a prime number generator in Ruby in order to learn the syntax, now I'm optimizing it to learn what works best. Here's the benchmark I put together: require 'base64';require 'zlib';puts Zlib.inflate(Base64.decode64("eJxlkMEOwiAQRO98hekFuGzxQEwPXvwR01ZqiYHqBk2Tln8XDlWgnDbM25nJonq9NaoD7ZTtR9PigxK09zM7AkgRHieXTYHOsBNf1nklM6B6TuhYpdp+rPgSdiCOi/d/kQ71QBOtAVFLEDly05+UYQ2H+MckL6z0zioDdJG1S9K1K4iQAW66DhnmiqRYKEJFXMByux+XuOJ2XdO60dKsjC7aBtyTL5O5hLk="))
One question, would it preserve the precision like we are using 'decimal'?
Is there any way to obtain integer if the result is integer. Someting like 17/2 = 8.5 and 16/2 = 8?
R
Renaud

You can check it with irb:

$ irb
>> 2 / 3
=> 0
>> 2.to_f / 3
=> 0.666666666666667
>> 2 / 3.to_f
=> 0.666666666666667

R
Rok Kralj

You can include the ruby mathn module.

require 'mathn'

This way, you are going to be able to make the division normally.

1/2              #=> (1/2)
(1/2) ** 3       #=> (1/8)
1/3*3            #=> 1
Math.sin(1/2)    #=> 0.479425538604203

This way, you get exact division (class Rational) until you decide to apply an operation that cannot be expressed as a rational, for example Math.sin.


The mathn module is deprecated since ruby 2.2
A
Andrew Marshall

Change the 5 to 5.0. You're getting integer division.


u
ucpuzz

Fixnum#to_r is not mentioned here, it was introduced since ruby 1.9. It converts Fixnum into rational form. Below are examples of its uses. This also can give exact division as long as all the numbers used are Fixnum.

 a = 1.to_r  #=> (1/1) 
 a = 10.to_r #=> (10/1) 
 a = a / 3   #=> (10/3) 
 a = a * 3   #=> (10/1) 
 a.to_f      #=> 10.0

Example where a float operated on a rational number coverts the result to float.

a = 5.to_r   #=> (5/1) 
a = a * 5.0  #=> 25.0