Live data from Hacker News

1.5 is the midpoint between 0 and infinity in Ruby

blog.peterzhu.ca

81–90 of 125 posts

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

#81

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.

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

#82
Like every blog post or article that talks about something weird related to IEEE floats, this absolutely needs to find a way to link to "What Every Computer Scientist Should Know About Floating-Point Arithmetic", over on https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.h..., because that's mandatory reading if you're programming.

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

#83
post #80

Earlier quoted context omitted.

Kind of but you get significantly better precision than if you just use a normal double float type because doubles only push the issues further out. Especially in games you're likely already breaking the world into cells for streaming chunks into/out of memory anyways.

Isn't this also just pushing the problem out? Once you get far enough out, you wouldn't be able to transition between cells because of the rounding error of the cell boundary being bigger than the cell size. You can't represent infinite precision with finite bits so you must run into an issue eventually.

Of course but remember that it grows exponentially with the number of bits. Every bit you add one bit it doubles your usable size.

The visible universe (according to Wikipedia) is 8.8 * 10^26 meters or about 5.4 * 10^61 Plank lengths. That gives us a log2 of 205.1

In other words if my maths is correct if you want to represent the entire visible universe down to the scale of the Planck length you need 206bits of resolution, or 4 64 bit integers with a lot of room to spare.

And if you don't actually aim to simulate subatomic particles you can get down to millimeter resolution with "only" 100bits.

And that's not even taking into account that, our universe being so empty, you can probably fudge super large distances a bit (having a lower resolution at scales where the universe is mostly empty). Nobody is going to notice if Andromeda if a few parsecs closer than it should be.

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

#84
post #76
post #29

In surreal numbers [1], the midpoint between 0 and infinity would be the simplest number greater than 0, which is { 0 | } = 1 [1] https://en.wikipedia.org/wiki/Surreal_number

This is also consistent with the old joke that developers count like cavemen: zero, one, many!

Well, if you map the contents of the unit circle (|z| 1. So there really is no need to give unique names to anything beyond 1 as it's already contained in the proverbial nutshell of the unit circle via 1/z.

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

#85
post #59

Earlier quoted context omitted.

From Python: >>> import numpy as np >>> 1 + np.Inf inf >>> (0 + np.Inf)/2 inf >>> Infinity is not a number it is a concept[1] My math teacher used to say think of infinity like a impossibly large number. An impossibly large number divided by two is still an impossibly large number [1] http://mathforum.org/dr.math/faq/faq.large.numbers.html

While you’re correct, you’re being downvoted probably because you’re taking this seriously. I’m sure most everyone here knows infinity isn’t a number, but a concept, but you never know.

[deleted]

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

#86

Clearly we'll need to some work in TruffleRuby to be fully compatible. I really hope nobody's code depends on this. Infinity 8.988465674311579e+307 4.4942328371557893e+307 2.2471164185778946e+307 1.1235582092889473e+307 5.6177910464447366e+306 ... 32767.999999999996 16383.999999999998 8191.999999999999 4095.9999999999995 2047.9999999999998 1023.9999999999999 511.99999999999994 255.99999999999997 127.99999999999999 63…

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 ieeeinteger 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 point).

The TruffleRuby binary search solution is also "correct" in its own way, in that it's binary searching using the actual floating point values themselves.

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

#87
post #76

Earlier quoted context omitted.

This is also consistent with the old joke that developers count like cavemen: zero, one, many!

Well, if you map the contents of the unit circle (|z| 1. So there really is no need to give unique names to anything beyond 1 as it's already contained in the proverbial nutshell of the unit circle via 1/z.

You don't even need the unit circle. The unit interval is enough, as is any set whose cardinality is aleph-1.

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

#88
post #29

In surreal numbers [1], the midpoint between 0 and infinity would be the simplest number greater than 0, which is { 0 | } = 1 [1] https://en.wikipedia.org/wiki/Surreal_number

TIL: apart from infinity (number, larger than any real number in absolute value) there are infinitesimal (number, less than any real number in absolute value and not a zero). Edit: also, those infinitesimals were the subject of political and religious controversies in 17th century Europe, including a ban on infinitesimals issued by clerics in Rome in 1632.

The theory of infinitesimals is intimately connected to how analysis (differential and integral calculus) was first formulated. Leibniz and Newton understood that you could approximate instant rates of change, or areas under a curve, by taking smaller and smaller "slices" of a function, but they did not yet have the rigorously formalized notion of limits that modern analysis depends on. So they developed an arithmetic of infinitesimals, numbers greater than zero but less than any positive real number¹, with some rather ad-hoc properties to make them work out in calculations.

Philosophical problems surrounding the perplexing concept of infinity were already hotly debated by the ancient Greeks. Aristotle made an ontological distinction between actual and potential infinities, and argued that actual infinity cannot exist but potential infinity can. This was also the consensus position of later scholars, and became a sticking point in the acceptance of calculus because infinitesimals (and infinite sums of them) were an example of the ontologically questionable actual infinities.

As I mentioned before, standard modern analysis is based on limits, not infinitesimals, and requires no extension of real numbers. Indeed the limit definition of calculus only requires the concept of potential infinities, so philosophers should be able to rest easy! But infinitesimals still occur in our notation which is largely inherited from Leibniz, however. We say that the derivative of y(x) is dy/dx, or the antiderivative of y(x) is ∫ y(x) dx, and while acknowledging that dy and dx are not actual mathematical objects, just syntax, we still do arithmetic on them whenever it's convenient to do so! For example, when we make a change of variables in an integral, we can substitute x = f(t) for some f, and then say dx/dt = f'(t) and "multiply by dt" to get dx = f'(t) dt to figure out what we should put in the place of the "dx" in the integral.

Actual infinitesimal numbers are not dead, either, they're used in a branch of analysis called nonstandard analysis which formalizes them in the logically rigorous manner that is now expected from mathematics.

________

¹ Not that they had a rigorous theory of real numbers, either, that came in the 19th and early 20th century. In fact what we now understand as formal, axiomatized math didn't really exist before the 19th century at all!

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

#89
post #14

I vaguely remember learning similar fact years ago, but it was phrased something like "There are as many floats in [0, 1] range as in [1, infty]". Leaving aside where exactly "midpoint" of floats lies (either in Ruby's implementation or other languages'): what would be implications of this for writing code dealing with floats? Can I shoot myself in the foot somehow with low precision if numbers I'm using are "too clo…

> Can I shoot myself in the foot somehow with low precision if numbers I'm using are "too close" to infinity?

The "number of sig figs" precision will be the same for large values far away from zero, as for values close to zero. E.g. IEEE 64 bit reliably gives you about 15 decimal digits of precision. Any decimal number with 15 digits of precision that is in the range of the IEEE 64 bit double can be converted to that type, and then back to decimal, such that all those digits of precision are recovered.

You can shoot yourself in the foot if you rely on floating-point values being able to exactly represent integers, but the values go beyond the range where that is possible. Beyond a certain range, all consecutive integers are no longer representable; some integers get approximated by nearby integers.

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

#90
post #70

C++ :) #include #include double midpoint(double first, double second) { auto firstAsInt = reinterpret_cast (first); auto secondAsInt = reinterpret_cast (second); auto mid = (secondAsInt + firstAsInt) / 2; return reinterpret_cast (mid); } int main() { std::cout 1.5 = " inf = " ::infinity())

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.
Post reply on HN