REBOL3 tracker
  0.9.12 beta
Ticket #0001622 User: anonymous

Project:

Previous Next
rss
TypeBug Statuscomplete Date20-Jun-2010 09:52
Versionalpha 99 CategoryNative Submitted byLadislav
PlatformAll Severitycrash Prioritynormal

Summary EVEN?, ODD? and decimals
Description I consider a value to be even only if it is an integral multiple of two. This means that for some purposes 2.1 is not even.

This begs a question how the EVEN? and ODD? functions shall be defined.

I also noticed that the present implementation of the functions uses code with undefined behaviour (thus the severity updated to crash).
Example code
>> even? 2.1
== true

Assigned ton/a Fixed inr3 master Last Update26-Jan-2015 06:13


Comments
(0002398)
Ladislav
25-Jun-2010 08:55

To be even more specific, here are my alternative functions to consider:

alternative-even?: func [
number [decimal!]
] [
zero? number // 2.0
]

alternative-odd?: func [
number [decimal!]
] [
found? all [
zero? number // 1.0
not zero? number // 2.0
]
]

; some results:
>> alternative-even? 2.1
== false

>> alternative-even? 2.0
== true

>> alternative-odd? 2.0
== false

>> alternative-odd? 2.1
== false

>> alternative-odd? 1.1
== false

>> alternative-odd? 1.0
== true
(0002510)
Carl
21-Sep-2010 20:11

The problem with this definition is that decimal values, being based on floats, may contain very small computational "rounding" errors.

The current definition of ODD? and EVEN? is that if the decimal values are truncated to integer, such as when used as an index value to a series, will they be odd or even. This seems reasonable.

Post a comment if you think otherwise.
(0003860)
Ladislav
15-May-2013 10:50

Well, I understand your concern. To summarize:

* floating point arithmetic is not real arithmetic
* any floating point operation (for example addition) can be described as performing the corresponding "real" operation followed by a rounding operation finding the nearest floating point number to the "real" result
* that means that results of (chains of) floating point operations are in some way "approximate", differing from the "real" results even in cases when "real results" would be "integral values" like 2.0, e.g.

Thus, it looks legitimate to strive for some "tolerance" - ability to tolerate "small differences from integers" in such case. However, does this implementation actually tolerate small differences from integer values?

To be able to judge, I define a couple of operations allowing ULP (unit in the last place) manipulations:

as-dec: func [value [integer!]] [to decimal! to binary! value]
as-int: func [value [decimal!]] [to integer! to binary! value]
add-ulp: func [value [decimal!] ulps [integer!]] [as-dec add as-int value ulps]

Some results:

>> add-ulp 2.0 0
== 2.0

>> add-ulp 2.0 1
== 2.0000000000000004

>> add-ulp 2.0 -1
== 1.9999999999999998

The results demonstrate the behaviour of the ADD-ULP function.

Note that +1 and -1 ULPs are the smallest possible differences between two distinct floating point numbers. If we strive for rounding tolerance, we shall tolerate (at least) +/- 1 ULP differences. So, is the +/- 1 ULP difference tolerated by the the current EVEN? function implementation?

even? 2.0 ; == true
even? add-ulp 2.0 -1 ; == false

Thus, we actually do not have even the smallest tolerance possible and the whole thing should be redesigned/reconsidered.
(0004014)
Ladislav
26-Sep-2013 00:26

If wanting to ignore small (< 0.5) errors, this is the variant to consider:

alternative-even?: func [
    number [decimal!]
] [
    number: abs number // 2.0
    case [
        number < 0.5 [true]
        number < 1.5 [false]
        'else [true]
    ]
]

alternative-odd?: func [
    number [decimal!]
] [
    number: abs number // 2.0
    case [
        number < 0.5 [false]
        number < 1.5 [true]
        'else [false]
    ]
]

Note: This is the most tolerant definition possible.

For example:

even? 1.9999999999999998 ; == true
even? 2.0 ; == true
even? 2.0000000000000004 ; == true
(0004017)
Ladislav
26-Sep-2013 14:15

EVEN? and ODD? fix working as above submitted as https://github.com/rebol/rebol/pull/151

Date User Field Action Change
26-Jan-2015 06:13 abolka Status Modified built => complete
26-Jan-2015 06:13 abolka Fixedin Modified => r3 master
11-Mar-2014 19:14 Ladislav Status Modified pending => built
28-Sep-2013 06:46 Ladislav Description Modified -
28-Sep-2013 06:44 Ladislav Description Modified -
27-Sep-2013 09:53 Ladislav Description Modified -
27-Sep-2013 09:53 Ladislav Description Modified -
27-Sep-2013 09:52 Ladislav Description Modified -
27-Sep-2013 09:50 Ladislav Status Modified waiting => pending
27-Sep-2013 09:50 Ladislav Severity Modified minor => crash
26-Sep-2013 14:16 Ladislav Comment : 0004017 Modified -
26-Sep-2013 14:15 Ladislav Comment : 0004017 Added -
26-Sep-2013 14:14 Ladislav Comment : 0004014 Modified -
26-Sep-2013 12:04 Ladislav Comment : 0004014 Modified -
26-Sep-2013 00:27 Ladislav Comment : 0004014 Modified -
26-Sep-2013 00:26 Ladislav Comment : 0004014 Added -
15-Aug-2013 14:29 Ladislav Category Modified Unspecified => Native
18-Jun-2013 15:48 Ladislav Comment : 0003860 Modified -
18-Jun-2013 15:45 Ladislav Comment : 0003860 Modified -
15-May-2013 15:38 Ladislav Comment : 0003860 Modified -
15-May-2013 15:35 Ladislav Comment : 0003860 Modified -
15-May-2013 15:35 Ladislav Comment : 0003860 Modified -
15-May-2013 10:50 Ladislav Comment : 0003860 Added -
21-Sep-2010 20:12 carl Status Modified reviewed => waiting
21-Sep-2010 20:11 carl Comment : 0002510 Added -
21-Sep-2010 20:06 carl Status Modified submitted => reviewed
25-Jun-2010 08:55 Ladislav Comment : 0002398 Added -
20-Jun-2010 09:55 Ladislav Description Modified -
20-Jun-2010 09:53 Ladislav Code Modified -
20-Jun-2010 09:53 Ladislav Description Modified -
20-Jun-2010 09:53 Ladislav Summary Modified EVEN? and decimals => EVEN?, ODD? and decimals
20-Jun-2010 09:52 Ladislav Ticket Added -