0

For example, take this IRB session:

1.9.3-p385 :046 > float = func_that_creates_large_float => 1.5815450433041317e+51 1.9.3-p385 :047 > float.to_i => 1581545043304131697954259018410479150921451567054848 

Can I be sure that the integer returned to me represents the same value as the float? I ask mainly because the Ruby documentation describes the to_i method on the Float class as "Returns the float truncated to an Integer". The word 'truncated' jumps out at me.

Edit: I think describing my situation would make it clear why I'm asking this. I'm trying to take the cube root of a large integer that I know will result in an integer as well. The cube root function uses a float to do its calculation, giving my result as a float. I need the NON-scientific-notation value and have no idea how to approach this.

Thank you.

4
  • 1
    Well you're converting a floating point number to an integer. Leaving aside really large values (where there wouldn't be any information at a smaller-than-integer precision anyway) what would you expect it to do for something like 1.4? That's why it's talking about truncation... Note that although I don't know much about Ruby, I don't believe there's any such thing as "a Ruby float in scientific notation" - there are values which are represented using x.ye+z when converted to a string... but that's just a text representation, not a fundamental difference between such values and ones like 1.5 Commented Aug 3, 2013 at 21:03
  • You're right, that makes my question look really silly. In my case the float ends in .0, so would there be no truncation? I stuck 'Ruby' in the title just to target my question; I get your point there. Commented Aug 3, 2013 at 21:12
  • Are you sure that float really is a float? What is the result of func_that_creates_large_float.class ? Commented Aug 3, 2013 at 23:46
  • Hi, the class is Float. I'm thinking I've asked the wrong question here, I should have posted something like "How to convert from a very large integer, to a float, and back, with no corruption of the value?" Commented Aug 3, 2013 at 23:53

2 Answers 2

1

On the contrary, (deterministic but meaningless) data is added (as you demonstrated in your code sample). You're not losing any information. But it's not the same value.

Your float has a precision of about 17 decimal digits, your int suddenly has a precision of 51 digits. This has to do with Floating Point Arithmetic: Issues and Limitations. That "precision" arises as the result of the binary representation of a decimal floating point value, which leads to the "invention" of a series of digits in your integer.

Consider the following (in Python, which follows the same rules, as will probably all programming languages that feature arbitrarily long integers):

>>> a = int(1.5815450433041317e+51) >>> a 1581545043304131697954259018410479150921451567054848 >>> b = a + 10000000000000000 >>> a == b False >>> float(a) == float(b) True >>> a == 1.5815450433041317e+51 True 

In Python, the decimal module would be quite a good compromise:

>>> from decimal import Decimal, getcontext >>> a = str(29873409852730498572309485723**3) # just an arbitrary number >>> getcontext().prec = 100 >>> cube = Decimal(a) >>> cube ** Decimal("0.333333333333333333333333333333333333333333333333333333333 33333333333333333333") Decimal('29873409852730498572309485722.99999999999999999999999999999999999999999 999998041297117811390088120595') 

(which still has a slight rounding error due to the problem of representing 1/3 as a decimal float, but the result is obvious, isn't it?)

Sign up to request clarification or add additional context in comments.

7 Comments

Great answer, I didn't know this about floating point numbers. It matters to me that I'm not achieving the same value. I updated my post with my specific situation, are you able to comment on it?
You need to use a different approach then. The cube root function will not have a high enough precision - the result will be wrong (as you can see when cubing the result you got).
Any suggestions? Is it just impossible to take the cube root of a large integer, then?
You'll need to roll your own, perhaps building from something like this.
@hlh: Does Ruby have a gem like Python's decimal module? That might do the trick.
|
1

Obviously, if the number of significant figures is greater than the magnitude of the exponent portion, then you will lose information during float to integer conversion.

Ruby (like many other programming languages) does not have a variable-precision floating point. Instead, the number of significant figures is fixed to a constant Float::DIG, which is 15 by default. That means, if you have a float smaller than 10^15, then you will lose information during float to integer conversion.


Regarding your question about the cubic root within integers, it is better to do the calculation within the Rational class. You don't need to worry about truncation.

(8 ** Rational("1/3")).to_r # => (2/1) 

2 Comments

Thanks for the suggestion, I gave the rationals a try and it still truncated my output unfortunately. Gave the same result as the scientific-notation float when I call .to_i on it.
What about changing Float::DIG to a larger number? If it does not work, then maybe Ruby is not the language for your need. Ruby is not good for numerical calculation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.