Live data from Hacker News

1.5 is the midpoint between 0 and infinity in Ruby

blog.peterzhu.ca

91–100 of 125 posts

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#91

Every time I see a bizarre mathematical output I am reminded that IEEE 754 is gross as hell. I just use bigints wherever it's possible to transform the algorithm to work with bigints, and I "render to decimal" in views

I disagree: IEEE 754 is quite elegant. The fact that they are monotonically increasing in correspondence to their bit representation is one of the many nice things about it.

IEEE 754 specifies some not-a-number values X that are not equal to themselves; i.e. such that X != X.

The bit pattern is actually not equal to itself: if we compared X bitwise, like with memcmp in C, it would be equal: memcmp(&X, &X, sizeof X) == 0.

That obnoxiously violates the philosophical Law of Identity, as we would like to see it applied in programming languages.

https://en.wikipedia.org/wiki/Law_of_identity

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#92

Earlier quoted context omitted.

Interesting -- there are more rows (incl removed rows) in yours, because the first step in TFA halves the exponent. I guess it behaves more like binary searching the list of numbers than binary searching the range of numbers, which should be more efficient when the distribution is so heavily skewed.

Yes, in fact we have a special version of bsearch to handle all the float corner cases, and part of that deals with the max being infinity [0], we can check that and then just try the largest finite floating point number. [0] ( https://github.com/oracle/truffleruby/blob/fde88d4019ab83716... )

Just a shout out that I really appreciate the work you guys are doing on GraalVM, especially the polyglot parts. It’s one of the more exciting parts of Graal that I don’t see too many people talk about, it’s usually all about native image and the JIT.

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#93

Every time I see a bizarre mathematical output I am reminded that IEEE 754 is gross as hell. I just use bigints wherever it's possible to transform the algorithm to work with bigints, and I "render to decimal" in views

I disagree: IEEE 754 is quite elegant. The fact that they are monotonically increasing in correspondence to their bit representation is one of the many nice things about it.

The lack of precision leads to increasing error over time in many contexts (off the top of my head, multiplication and division). I still think that if an algorithm can be rewritten to work with ints instead of floats, it will be served better the vast majority of the time.

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#94
post #54
post #43

Earlier quoted context omitted.

Some other senses in which 1 can be thought of as the "midpoint" between 0 and ∞ come from the many common ways to invertibly map an interval onto (0, ∞), in which the midpoint of that interval maps onto 1. For example: • tan maps (0, π/2) onto (0, ∞), and tan(π/4) = 1. • f(x) = x/(1 - x) maps (0, 1) onto (0, ∞), and f(1/2) = 1. • exp is an isomorphism from the reals under addition to the positive reals under multipl…

I have a question If this was true: tan maps (0, π/2) onto (0, ∞), and tan(π/4) = 1 Wouldnt it imply that tan(π/8) would be halfway between 0 and 1 ie .5? By my calculations it is 0.414 or √2 - 1 ALso with: • f(x) = x/(1 - x) maps (0, 1) onto (0, ∞), and f(1/2) = 1. wouldnt this mean that f(0.25) is supposed to be half way between 0 and 1 or .5. However f(0.25) = 0.25/0.75 = 1/3

> tan(π/8) would be halfway between 0 and 1 ie .5?

It implies that tan(π/8) would be "halfway" between 0 and 1 in this sense of what "halfway" means. In this sense, 0.5 is not halfway between 0 and 1, 0.414 is.

It's easier to visualize it. You're standing on the roof of a 1-meter-tall building on a flat earth with a perfectly clear atmosphere. If you look straight out (90°) you can see to infinity (tan 90°). If you look down (0°) you can see where you are (tan 0°). If you look halfway between those (45°), you can see 1 (tan 45°) meter straight in front of you. But if you look halfway down again, you won't see exactly 0.5 meters, will you?

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#95

Earlier quoted context omitted.

Rant: Technically , that code invokes undefined behavior as you use `reinterpret_cast` to alias variables. The only standards conforming way (prior to `std::bit_cast`[0] in C++20) was to use `memcpy`.[a] `reinterpret_cast` was added for situations where code you have no control over requires a certain type, but you need to force it to take your variable.[b] [a]: As `memcpy` (in addition to reinterpreting bits) copies…

memcpy certainly violates aliasing rules. You can access an object as an array of bytes, but you can't memcpy an object to one of a different type and then access it as that type without invoking undefined behavior.

memcpy() by itself cannot violate aliasing rules. By definition, char can alias any object.

Whether you can access an object that has been memcpy()'d into is a separate question. I can't find specific language about this, but I strongly suspect that the result is implementation-defined or unspecified (not undefined), unless there is a possibility of a trap representation.

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#96

Earlier quoted context omitted.

Rant: Technically , that code invokes undefined behavior as you use `reinterpret_cast` to alias variables. The only standards conforming way (prior to `std::bit_cast`[0] in C++20) was to use `memcpy`.[a] `reinterpret_cast` was added for situations where code you have no control over requires a certain type, but you need to force it to take your variable.[b] [a]: As `memcpy` (in addition to reinterpreting bits) copies…

memcpy certainly violates aliasing rules. You can access an object as an array of bytes, but you can't memcpy an object to one of a different type and then access it as that type without invoking undefined behavior.

Not true. You actually can. Aliasing is about viewing the same bits as two different types (what `reinterpret_cast`, union-based type punning, and cast pointers do) `memcpy` copies the bits to a new location which doesn’t violate aliasing. I don’t have time to find the reference in the standard, but cppreference.com[0] says it’s ok:

> Where strict aliasing prohibits examining the same memory as values of two different types, std::memcpy may be used to convert the values.

[0]: https://en.cppreference.com/w/cpp/string/byte/memcpy

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#97

Earlier quoted context omitted.

I'm left wondering if this is real behavior, or you're doing a Douglas Adams joke...

The 42 comes from the article itself. Both solutions make sense... the blog post refers to a ieee integer representation hack that likely finds answers faster, because it more quickly finds the values that tend to be in realistic numbers. It works by doing a binary search of all possible values representable in floating point (of which there are more for smaller numbers, due to the design tradeoff of IEEE floating po…

I doubt that 42.0 > 42

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#98
post #97

Earlier quoted context omitted.

The 42 comes from the article itself. Both solutions make sense... the blog post refers to a ieee integer representation hack that likely finds answers faster, because it more quickly finds the values that tend to be in realistic numbers. It works by doing a binary search of all possible values representable in floating point (of which there are more for smaller numbers, due to the design tradeoff of IEEE floating po…

I doubt that 42.0 > 42

That's the list of checks made by the bsearch algorithm. It will have to do at least one check near the end that's EDIT: It will also be probing to the ULP level, which the print could be rounding to 42.0. That could explain why there are at least two checks of "42.0".

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#99
post #54
post #43

Earlier quoted context omitted.

Some other senses in which 1 can be thought of as the "midpoint" between 0 and ∞ come from the many common ways to invertibly map an interval onto (0, ∞), in which the midpoint of that interval maps onto 1. For example: • tan maps (0, π/2) onto (0, ∞), and tan(π/4) = 1. • f(x) = x/(1 - x) maps (0, 1) onto (0, ∞), and f(1/2) = 1. • exp is an isomorphism from the reals under addition to the positive reals under multipl…

I have a question If this was true: tan maps (0, π/2) onto (0, ∞), and tan(π/4) = 1 Wouldnt it imply that tan(π/8) would be halfway between 0 and 1 ie .5? By my calculations it is 0.414 or √2 - 1 ALso with: • f(x) = x/(1 - x) maps (0, 1) onto (0, ∞), and f(1/2) = 1. wouldnt this mean that f(0.25) is supposed to be half way between 0 and 1 or .5. However f(0.25) = 0.25/0.75 = 1/3

> tan(π/8) would be halfway between 0 and 1 ie .5?

tan(π/8) = √2 - 1, not 1/2, but the value is indeed halfway between 0 and 1 if you take the distance function to be

d(a, b) = |b - a| / (√(1 + a²)√(1 + b²)) or

d(a, b) = |b - a| / |1 + ab|

(These are chordal distance or stereographic distance, respectively, when the real number line is used to represent points on a circle under stereographic projection.)

The halfway point is 0.5 when you use the distance function d(a, b) = |b - a|.

Re: 1.5 is the midpoint between 0 and infinity in Ruby

#100

Earlier quoted context omitted.

I disagree: IEEE 754 is quite elegant. The fact that they are monotonically increasing in correspondence to their bit representation is one of the many nice things about it.

The lack of precision leads to increasing error over time in many contexts (off the top of my head, multiplication and division). I still think that if an algorithm can be rewritten to work with ints instead of floats, it will be served better the vast majority of the time.

Multiplication and division of floats creates rounding errors of The operations you need to watch out for are addition/subtraction, in cases where your result has much smaller magnitude than your inputs, causing loss of significance. Sometimes great care must be taken in implementing numerical algorithms to avoid this. But this is an inherent problem in numerical computing, not the fault of the floating point format per se.
Post reply on HN