## Feature #5321

### Introducing Numeric#exact? and Numeric#inexact?

**Description**

Ruby has several numeric classes such as Integer.

These classes are classified whether their instances represent numbers exactly.

According to this, Integer and Rational are exact, and Float and BigDecimal are inexact because they're always including error.

The exactness of a Complex depends on its real and imaginary parts.

Now, Ruby's numeric classes doesn't provide predicators to investigate the exactness of their instances.

So, if we want to examine whether a number is exactly zero, we must investigate the class of the number.

I want simple way to examine the number exactness.

I propose to introduce Numeric#exact? and/or Numeric#inexact? for resolving this inconvenience.

**Related issues**

### History

#### #1 Updated by naruse (Yui NARUSE) almost 6 years ago

**Project**changed from*Ruby trunk*to*CommonRuby***Category**deleted ()*core***Target version**deleted ()*Next Major*

#### #2 Updated by naruse (Yui NARUSE) almost 6 years ago

**Project**changed from*CommonRuby*to*Ruby trunk*

#### #3 [ruby-core:40514] Updated by alexeymuranov (Alexey Muranov) almost 6 years ago

I like this proposal. -Alexey.

#### #4 [ruby-core:40519] Updated by headius (Charles Nutter) almost 6 years ago

Why is BigDecimal considered inexact? Unlike a float, a value in a BigDrcimal is always represented exactly. The value itself may be and estimate for various reasons (irrational, repeating, ...), but that is a property of the value, not a property of BigDecimal. Or put another way, BigDecimal is not inexact since if it is possible to exactly represent the number in base 10, BigDecimal can represent it exactly.

Perhaps the idea of inexact is too fuzzy here...even Float can be exact if the value can be exactly represented in base 2 decimal form with Float's precision.

It seems to me that the interesting characteristic of these classes is not whether the value they represent is exact, but whether arithmetic operations using them can be done exactly. By that definition, only Float is clearly inexact; even if the two operands of a floating-point arithmetic operation are exact, the result may not be. The other types do not have this property.

#### #5 [ruby-core:40524] Updated by alexeymuranov (Alexey Muranov) almost 6 years ago

Charles, this is from the documentation of BigDecimal: "If a computation results in a value which is too small to be represented as a BigDecimal within the currently specified limits of precision, zero must be returned.".

Thus the operations on BigDecimal are not exact. (See also BigDecimal::ROUND_MODE.)

For me it is easier to think simply whether a class is *intended* to represent numbers exactly.

Clearly it is better to represent a number exactly whenever the exact value can possibly be defined, can possibly be encoded into a sequence of bytes, when this representation would not take up all of the computer's memory, when carrying out exact computations would not be taking too much time, and if additionally a corresponding class exists in Ruby.

One would probably use Float or BigDecimal to store the distance between CERN and Gran Sasso, but Rational to store an image aspect ratio when this aspect ratio is rational.

The formal definition of exactness probably is the following: "Each operation must be carried out exactly or return NaN or nil, or return some other *exceptional* value."

-Alexey.

#### #6 [ruby-core:40553] Updated by regularfry (Alex Young) almost 6 years ago

On 30/10/11 12:29, Alexey Muranov wrote:

Issue #5321 has been updated by Alexey Muranov.

Charles, this is from the documentation of BigDecimal: "If a computation results in a value which is too small to be represented as a BigDecimal within the currently specified limits of precision, zero must be returned.".

Thus the operations on BigDecimal are not exact. (See also BigDecimal::ROUND_MODE.)For me it is easier to think simply whether a class is

intendedto represent numbers exactly. The formal definition of exactness probably is the following: "Each operation must be carried out exactly or return NaN or nil, or return some otherexceptionalvalue."

The problem with this is that the values *are* exact, and *some* of the

operations are inexact. Some of the operations are *sometimes* inexact.

Flagging a class at a time as exact or inexact just sounds wrong to me.

Better would be flagging values that have had inexact operations

performed on them (or exact operations with an inexact operand) at any

time in their history, but I've no idea how you'd do that while keeping

any sort of respectable performance.

--

Alex

## -Alexey.¶

Feature #5321: Introducing Numeric#exact? and Numeric#inexact?

http://redmine.ruby-lang.org/issues/5321Author: Kenta Murata

Status: Open

Priority: Normal

Assignee: Yukihiro Matsumoto

Category:

Target version:Ruby has several numeric classes such as Integer.

These classes are classified whether their instances represent numbers exactly.

According to this, Integer and Rational are exact, and Float and BigDecimal are inexact because they're always including error.

The exactness of a Complex depends on its real and imaginary parts.Now, Ruby's numeric classes doesn't provide predicators to investigate the exactness of their instances.

So, if we want to examine whether a number is exactly zero, we must investigate the class of the number.

I want simple way to examine the number exactness.I propose to introduce Numeric#exact? and/or Numeric#inexact? for resolving this inconvenience.

#### #7 Updated by mame (Yusuke Endoh) almost 6 years ago

**Status**changed from*Open*to*Rejected*

#5321 と重複です。あちらで議論しましょう。

あちらの議論がまとまった上での作業は大歓迎です。

--

Yusuke Endoh mame@tsg.ne.jp

#### #8 [ruby-core:40555] Updated by mame (Yusuke Endoh) almost 6 years ago

**Status**changed from*Rejected*to*Assigned*

Oops, sorry, I've closed this ticket by error. Reopen.

--

Yusuke Endoh mame@tsg.ne.jp

#### #9 [ruby-core:40556] Updated by mame (Yusuke Endoh) almost 6 years ago

Hello,

2011/9/14 Kenta Murata muraken@gmail.com:

Now, Ruby's numeric classes doesn't provide predicators to investigate the exactness of their instances.

So, if we want to examine whether a number is exactly zero, we must investigate the class of the number.

I want simple way to examine the number exactness.

Can you show any actual use case?

--

Yusuke Endoh mame@tsg.ne.jp

#### #10 [ruby-core:40557] Updated by alexeymuranov (Alexey Muranov) almost 6 years ago

I misread the proposal, it was actually about adding instance `Numeric#exact?`

method, and not class `Numeric.exact?`

method.

For me, adding class method `Numeric.exact?`

would be good enough.

To examine the exactness of a value, it would be enough to call `val.class.exact?`

.

As Alex pointed out, this is better for performance, and it seems to me easier to assume that Float is always inexact than to inspect its instances.

I think it helps distinguishing classes that are *intended* to represent numbers exactly from those that are not. Those that are intended for this, should carry out standard arithmetic exactly, or return an exceptional value.

Sorry, i change my mind, i am more in favor of `Numeric.exact?`

. A new subclass of `Numeric`

can implement `#exact?`

, or maybe interval arithmetic would even be better (http://en.wikipedia.org/wiki/Interval_arithmetic).

-Alexey.

#### #11 [ruby-core:40558] Updated by mrkn (Kenta Murata) almost 6 years ago

Charles Nutter wrote:

Why is BigDecimal considered inexact?

As Alexey pointed out, the reason is from BigDecimal's definition.

A BigDecimal represents an *approximation* of a real number, not a rational number.

#### #12 [ruby-core:40559] Updated by tadf (tadayoshi funaba) almost 6 years ago

i've proposed this before 1.9.

and i've virtually used those predicates in Complex/Rational internally.

i've taken those from scheme.

scheme's one accept also complex number.

i think those should be instance methods.

(exact? 1+0i)

#t

(exact? 1+0.0i)

#f

bye

#### #13 [ruby-core:40560] Updated by mrkn (Kenta Murata) almost 6 years ago

Yusuke Endoh wrote:

Can you show any actual use case?

I want to create a mathematical function which behaves like 1/x.

This function is defined over real numbers except for zero,

because lim_{x -> +0} 1/x = +inf while lim_{x -> -0} 1/x = -inf.

So I want to raise Math::DomainError for the function with exact zero.

But I don't want to raise the error for inexact zeros, such as 0.0, -0.0,

BigDecimal("0"), and others which are instances of classes I don't know.

If Numeric#inexact? and Numeric#exact? are given,

I can realize the function more easily.

#### #14 [ruby-core:40561] Updated by alexeymuranov (Alexey Muranov) almost 6 years ago

Kenta Murata wrote:

So I want to raise Math::DomainError for the function with exact zero.

But I don't want to raise the error for inexact zeros, such as 0.0, -0.0,

BigDecimal("0"), and others which are instances of classes I don't know.

In my opinion, checking `x.class.exact?`

would be good enough. If you will be checking the instance property #exact? for inputs, you are likely to find most input floats inexact, if they were produced as output of other operations, as operations on floats are not *intended* to be exact. I think that all exact values should be grouped in separate classes, like Rational, distinguished by their *intended* use. (Isn't the different intended uses the reason to have more than one class?) It may make sense to me to create a subclass of Numeric where each value is exact or inexact.

As a use case for `Numeric.exact?`

i can only think about using it in irb to not have to look up documentation, or to have a program that needs to carry out computations exactly and that dynamically chooses or tests an appropriate class to work with (so indeed the program will be testing whether the *methods* of a class are exact before calling them).

#### #15 [ruby-core:40563] Updated by mame (Yusuke Endoh) almost 6 years ago

Hello,

2011/10/31 Kenta Murata muraken@gmail.com:

I want to create a mathematical function which behaves like 1/x.

This function is defined over real numbers except for zero,

because lim_{x -> +0} 1/x = +inf while lim_{x -> -0} 1/x = -inf.

So I want to raise Math::DomainError for the function with exact zero.

But I don't want to raise the error for inexact zeros, such as 0.0, -0.0,

BigDecimal("0"), and others which are instances of classes I don't know.If Numeric#inexact? and Numeric#exact? are given,

I can realize the function more easily.

Thank you for the explanation.

You expect that 1/x does never raise any exception if x is an

inexact number, right? I wonder if the expectation is valid.

But anyway, your use case is certainly convincing for me.

Thank you.

--

Yusuke Endoh mame@tsg.ne.jp

#### #16 [ruby-core:40565] Updated by mame (Yusuke Endoh) almost 6 years ago

Hello,

2011/10/31 tadayoshi funaba redmine@ruby-lang.org:

i've taken those from scheme.

scheme's one accept also complex number.

i think those should be instance methods.

I guess Scheme's exactness differs from this proposal.

Scheme's exactness is orthogonal to the type. Actually, the spec of

Scheme allows an "inexact integer" and "exact real."

So it makes no sense to quote Scheme.

But I don't mean that I'm against the proposal. I think the proposal

is fine even if it is different from Scheme's.

--

Yusuke Endoh mame@tsg.ne.jp

#### #17 [ruby-core:40566] Updated by mrkn (Kenta Murata) almost 6 years ago

Alexey Muranov wrote:

In my opinion, checking

`x.class.exact?`

would be good enough.

I don't think so for two reason.

First, I think the form of "x.class.exact?' isn't ruby way, and too long than "x.exact?".

Second, it limits the exactness property for class.

Numeric classes including both exact and inexact instances should be allowed, I think.

#### #18 [ruby-core:40567] Updated by tadf (tadayoshi funaba) almost 6 years ago

But I don't mean that I'm against the proposal. I think the proposal is fine even if it is different from Scheme's.

i'm ok too, even if you don't understand at all what i mean.

#### #19 [ruby-core:40570] Updated by alexeymuranov (Alexey Muranov) almost 6 years ago

Kenta Murata wrote:

Alexey Muranov wrote:

In my opinion, checking

`x.class.exact?`

would be good enough.I don't think so for two reason.

First, I think the form of "x.class.exact?' isn't ruby way, and too long than "x.exact?".

Second, it limits the exactness property for class.Numeric classes including both exact and inexact instances should be allowed, I think.

I am not against Numeric classes including both exact and inexact instances :).

I just doubt it is a good idea to define this in the base Numeric class itself, it would look too heavy to me. (Being able to check whether a given integer is exact? does not look valuable to me.) It sounds like what Yusuke Endoh said about exactness in Scheme (which i do not know). This would probably mean that you need to set the exactness flag for the first time when you read a value from the input, or it should be set to inexact by default (or, even worse, to exact or inexact depending on the default for the class), which will make you think if your output is inexact because an inexact operation was carried out, or because the exact flag was not set correctly on the first input.

I see benefit in being able to mix exact and inexact values, but it can be done even if exactness is defined on the (sub)class level. Keeping track of what influences exactness of your value seems easier if you know that it is a class property.

Update: i just thought about another argument against instance #exact? method. Please correct me if i am wrong: isn't the state of every Numeric object completely defined by its numeric value (in addition to its class)? If so, adding a second attribute (exacteness) to all Numeric instances will seem like a drastic change.

#### #20 Updated by mrkn (Kenta Murata) almost 6 years ago

**Status**changed from*Assigned*to*Rejected*

#### #21 [ruby-core:40622] Updated by tarui (Masaya Tarui) almost 6 years ago

**Status**changed from*Rejected*to*Assigned*

maybe miss operation

#### #22 [ruby-core:49681] Updated by mame (Yusuke Endoh) almost 5 years ago

**Target version**set to*next minor*