00:00:00.000
ready for takeoff
00:00:18.539
hello rubyconf my name is Peter I'm on
00:00:21.960
the Ruby core team and I'm a senior
00:00:23.699
developer at Shopify based out of Ottawa
00:00:26.400
Canada
00:00:27.900
today I'll be talking about why 1.5 is
00:00:30.599
the midpoint between 0 and infinity
00:00:33.360
so what do I mean when I say that 1.5 is
00:00:36.420
the midpoint between 0 and infinity
00:00:39.899
it all started when a co-worker asked
00:00:42.300
this question on Slack
00:00:44.100
why is 1.5 the first number Ruby's
00:00:46.980
binary search inspects when searching
00:00:49.379
between 0 and infinity and attach this
00:00:52.440
code snippet
00:00:54.300
the question and the code were both a
00:00:56.160
bit odd to be because how can you search
00:00:58.500
over an infinite range and how is 1.5
00:01:01.559
related to this in any way
00:01:04.260
well let's first take a look at this
00:01:06.299
short Ruby code
00:01:08.280
first creating a range between 0 and
00:01:10.560
infinity
00:01:11.700
it's then calling the range B search
00:01:14.700
method over that range
00:01:17.220
we then output every number that we
00:01:19.439
inspect
00:01:20.580
and then the block returns a Boolean
00:01:22.680
whether the floating Point number passed
00:01:24.659
in is greater than 42 or not
00:01:27.299
essentially we're looking for the First
00:01:29.400
floating Point number that is strictly
00:01:31.439
greater than 42.
00:01:33.840
now let's run this script and seal the
00:01:36.540
output
00:01:41.400
we see a lot of numbers that it inspects
00:01:43.740
with the first number being 1.5 followed
00:01:47.280
by a lot of very large numbers that are
00:01:49.619
seemingly random
00:01:51.119
and then we see the numbers converging
00:01:52.860
closer and closer to 42.
00:01:55.500
so how does range B search figure out
00:01:57.479
what numbers to inspect here
00:01:59.820
in order to understand this output we
00:02:02.159
first have to understand how binary
00:02:03.720
search works and then how floating Point
00:02:05.880
numbers work
00:02:07.979
but before we talk about how binary
00:02:10.140
search works let's talk about how linear
00:02:12.420
search works
00:02:13.620
it's really simple we simply just
00:02:16.140
inspect every element in the list and
00:02:18.840
compare whether or not it's equal to the
00:02:20.520
element we're looking for
00:02:22.200
let's look at an example let's see what
00:02:24.540
let's say we're trying to find the
00:02:25.739
number 15 from this array of integers
00:02:28.620
with linear search we simply scan from
00:02:31.020
the start of the array and check if each
00:02:32.459
element is equal to 15 the elements
00:02:34.500
we're searching for
00:02:35.640
until we find the integer 15 in our
00:02:38.220
array simple right
00:02:40.980
now let's see how binary search works
00:02:43.019
however before we can do that we need a
00:02:46.080
restriction on the list that we're
00:02:47.760
searching over
00:02:48.900
it has to be sorted in either ascending
00:02:51.120
or descending order
00:02:53.040
let's see an example using the same
00:02:54.900
array of integers but sorted in
00:02:56.819
ascending order
00:02:58.379
again we'll try to find the integer 15
00:03:00.540
from this list
00:03:02.220
to use binary search we need to have two
00:03:04.440
cursors a low cursor that points to the
00:03:07.620
first element of the array
00:03:09.900
and a high cursor that points to the
00:03:12.180
last element of the array
00:03:14.040
the two cursors Define the window which
00:03:16.080
we're searching over
00:03:17.519
using these two cursors we'll calculate
00:03:20.519
a third cursor called the mid cursor
00:03:22.620
that points to the element at the
00:03:24.360
midpoint
00:03:25.560
we compared the value of the elements at
00:03:27.540
the midpoint to 15. the elements the
00:03:29.760
number that we're searching for
00:03:31.379
since 48 is greater than 15 we move the
00:03:34.620
high cursor to the mid cursor
00:03:37.440
in a single comparison we just halved
00:03:40.019
the number of elements we're searching
00:03:41.580
over
00:03:42.420
because we know that 15 must be in the
00:03:44.940
window between the low and the high
00:03:46.739
cursors
00:03:48.360
and we repeat this process again
00:03:50.580
using the low and the high cursors will
00:03:52.680
calculate a mid cursor at the index
00:03:54.540
halfway between them which is at integer
00:03:56.819
12. we'll compare 12 and 15 since 12 is
00:03:59.879
less than 15 we'll move the low cursor
00:04:02.519
to the mid cursor
00:04:04.500
once again this comparison half the
00:04:06.720
number of elements we're searching over
00:04:09.299
and we'll repeat this process once again
00:04:11.519
using the low and the high cursors will
00:04:13.560
calculate a mid cursor at the integer 15
00:04:16.079
compare 15 and 15 since they're equal we
00:04:19.440
found the elements we're searching for
00:04:22.079
in the time it took me to explain binary
00:04:24.000
search I could have probably explained
00:04:25.979
linear search five times it's so
00:04:28.080
complicated so why do we use it
00:04:31.320
because if the list is sorted then
00:04:33.720
binary search is much faster especially
00:04:36.479
when we're searching over a large number
00:04:38.220
of elements
00:04:39.479
take a look at this graph the horizontal
00:04:42.120
x-axis shows the number of elements
00:04:44.340
we're searching over
00:04:45.780
and the vertical y-axis shows the number
00:04:48.419
of comparisons we have to do in the
00:04:50.220
worst case
00:04:51.300
for the compare for the computer
00:04:52.560
scientists here you might have heard of
00:04:54.419
The Big O complexity and that's what
00:04:56.340
we're graphing here
00:04:58.259
for linear search we have to do
00:04:59.880
comparisons equal to the number of
00:05:01.620
elements we're searching over in the
00:05:03.300
worst case
00:05:04.380
and this is graphed here as the red line
00:05:06.960
for binary search since every comparison
00:05:09.540
has the number of elements we consider
00:05:12.479
this results in comparisons equal to the
00:05:15.360
logarithm of the base two of the number
00:05:17.580
of elements in the worst case this is
00:05:19.919
graphed here as the blue line
00:05:21.720
we can see that the blue line is
00:05:23.580
significantly lower than the red line
00:05:25.560
for example for an array of 100 elements
00:05:28.560
then your search would have to do at
00:05:30.539
most 100 comparisons whereas binary
00:05:32.580
search would only need to do at most
00:05:34.259
seven comparisons
00:05:37.199
we just looked at how to perform binary
00:05:39.180
search over a sorted array which has
00:05:41.639
finite size and definite endpoints
00:05:44.699
so now you might be asking how can we
00:05:46.919
perform binary search over floating
00:05:48.780
Point numbers there seems to be an
00:05:50.639
infinite number of floating Point
00:05:51.780
numbers and on top of that we're binary
00:05:54.360
searching between 0 and infinity so how
00:05:56.940
is infinity a finite endpoint
00:06:00.600
in order to understand how we can binary
00:06:02.880
search in a range of between 0 and
00:06:05.039
infinity we first have to understand how
00:06:07.620
floating Point numbers are represented
00:06:09.419
internally
00:06:10.500
in particular I'll be talking about how
00:06:12.900
IEEE 754 floating Point numbers are
00:06:15.780
represented
00:06:16.860
all modern CPU architectures we use
00:06:19.020
nowadays such as x86 arm and risk 5 all
00:06:23.580
use IEEE 754 floating Point numbers
00:06:25.979
internally
00:06:27.240
so what I'm about to show you applies to
00:06:29.100
all modern computers
00:06:31.319
for Simplicity I'll be talking about
00:06:33.120
32-bit floating Point numbers also known
00:06:35.520
as single Precision floating Point
00:06:37.319
numbers
00:06:38.220
however Ruby uses 64-bit floating Point
00:06:40.620
numbers internally also known as double
00:06:42.600
Precision floating Point numbers
00:06:44.520
they both work in the same way it's just
00:06:46.740
that 64 bits will be to represent more
00:06:48.960
Precision than 32 bits
00:06:51.720
there are three parts to an IEEE 754
00:06:54.660
floating Point number
00:06:57.360
so one way to explain how these three
00:06:59.160
parts work would be to throw a formula
00:07:00.780
like this at you however I find this to
00:07:03.000
be unintuitive and difficult to
00:07:04.680
understand
00:07:05.819
so I'll move this off to the side and
00:07:07.740
I'll try to explain this using a
00:07:09.180
different approach
00:07:11.699
so first we have the sign
00:07:14.400
this one's pretty self-explanatory it's
00:07:16.800
a single bit that's zero when the number
00:07:18.780
is positive and one when it's negative
00:07:22.380
it's Then followed by the exponent
00:07:25.560
the exponent is 8 Bits in size meaning
00:07:28.020
that the value can range between 0 and
00:07:30.240
255.
00:07:31.979
intuitively the exponent tells us the
00:07:34.259
range which this floating Point number
00:07:35.880
falls into
00:07:37.139
ranges start at the power of 2 and end
00:07:39.539
at the next Power of Two
00:07:41.880
compared to using something like say
00:07:43.620
linear ranges using powers of 2 will let
00:07:46.560
us represent both very large and very
00:07:48.660
small numbers in magnitude
00:07:51.300
this table shows some of the exponent
00:07:53.460
values in decimal on the left and the
00:07:55.680
ranger corresponds to on the right
00:07:58.020
the square bracket on the left hand side
00:08:00.240
of the range means that the starting
00:08:02.039
point is inclusive and the round bracket
00:08:04.680
on the right hand side of the range
00:08:06.060
means that the end point is exclusive
00:08:09.479
ranges start at 2 to the power of the
00:08:11.580
exponent minus 127.
00:08:14.580
and ends at the next power of two we
00:08:17.039
subtract 127 so we are able to have
00:08:19.620
ranges to represent numbers with
00:08:21.180
magnitudes between 0 and 1.
00:08:24.060
for example an exponent with value 125
00:08:27.419
starts at 2 to the power of negative 2
00:08:29.220
which is 0.25 and ends at 2 to the power
00:08:32.279
of negative 1 which is 0.5
00:08:36.120
now that we know the range that the
00:08:37.979
floating Point number is in from the
00:08:39.659
exponent part the significant tells us
00:08:42.719
where the number is in the range
00:08:45.660
using 23 bits the significant can range
00:08:48.480
between 0 and 2 to the power of 23 minus
00:08:51.660
1.
00:08:52.800
this divides the range into 2 to the
00:08:54.720
power of 23 parts
00:08:56.459
which is about 8.4 Million Parts
00:09:00.720
the significant tells us how far into
00:09:03.180
the range the floating Point number lies
00:09:05.760
and the significance splits the range
00:09:07.920
into 8.4 million even parts
00:09:11.040
it's interesting to note that because
00:09:13.019
the significant can only divide the
00:09:15.000
range into a finite number of parts
00:09:17.580
it means that certain numbers cannot be
00:09:19.560
precisely represented as floating Point
00:09:21.959
numbers
00:09:23.160
you can actually see the consequences of
00:09:25.320
this
00:09:26.279
try opening up IRB or Ruby script and
00:09:28.920
try to add 0.1 and 0.2
00:09:31.560
you get into a result that's not quite
00:09:33.480
0.3
00:09:35.100
why this is is left as an exercise for
00:09:37.740
you to think about after this talk
00:09:40.920
let's see an example of a floating Point
00:09:43.019
number
00:09:44.220
let's try converting this floating Point
00:09:46.140
number which is in binary into a decimal
00:09:48.720
number
00:09:49.920
we see that the sign is zero meaning
00:09:51.720
that this is a positive number
00:09:54.060
now let's convert the exponent into a
00:09:55.860
decimal number it's the number at 130.
00:09:59.760
this corresponds to the range that
00:10:01.560
starts at 2 to the power over 3 which is
00:10:03.420
8 and enter 2 to the power 4 which is
00:10:05.519
16.
00:10:07.260
the significant corresponds to this
00:10:09.180
decimal number which is about 2.6
00:10:11.339
million
00:10:12.480
to get how far into the range between 8
00:10:14.760
and 16 this floating Point number is in
00:10:17.399
we divide this number by the 2 to the
00:10:19.440
power of 23 number which is this 8.38
00:10:22.560
Million number
00:10:24.060
and we get
00:10:25.940
0.3125 this means that we are 31.25 of
00:10:30.779
the range into eight between the range 8
00:10:33.660
and 16. and we can calculate this to be
00:10:36.420
the number 10.5
00:10:38.160
so these bits represent the number 10.5
00:10:40.560
in floating point
00:10:43.620
now that you've seen how binary search
00:10:45.600
works and how IEEE 754 floating Point
00:10:48.959
numbers work let's see how these two
00:10:51.240
concepts tie together
00:10:53.880
but before we can tie binary search and
00:10:55.920
floating Point numbers together let's
00:10:57.839
look at how the special floating Point
00:10:59.220
number is 0 and infinity are represented
00:11:02.579
for xero it's simply represented by all
00:11:05.160
of the bits being zero
00:11:07.500
for Infinity it's represented by the
00:11:11.040
exponent being all ones and the
00:11:12.839
significant being all zeros
00:11:15.120
note that this is the largest possible
00:11:17.399
floating Point number since IEEE 754
00:11:20.760
uses an exponent of all wines and a
00:11:23.160
non-zero significant to denote the value
00:11:25.320
not a number
00:11:26.880
this value is used to signal that this
00:11:29.700
floating Point number is invalid
00:11:32.579
all right let's go back to these two
00:11:34.140
numbers
00:11:35.100
and let's try to do something that's
00:11:36.839
perhaps a little strange
00:11:38.880
what if we read these floating Point
00:11:40.800
numbers as if they were 32-bit integers
00:11:44.279
for the floating Point number zero it'd
00:11:46.560
Simply Be zero as an integer
00:11:49.019
for the floating Point number infinity
00:11:50.660
it'll be this number that's about 2.1
00:11:53.399
billion
00:11:54.480
again it's important to note that what
00:11:56.880
we're doing here is we're directly
00:11:58.680
reading the bits of the floating Point
00:12:00.360
number as if it was an integer
00:12:03.000
and this is different than casting a
00:12:05.279
floating Point number to an integer
00:12:07.440
we cannot cast a floating Point numbers
00:12:09.839
Infinity into an integer since integers
00:12:12.720
do not have the concept of infinity
00:12:15.240
and Ruby if you try to convert Infinity
00:12:18.120
into an integer an error will be raised
00:12:21.540
in the C language however it will result
00:12:24.120
in undefined Behavior and the result
00:12:26.279
will depend on the system
00:12:28.920
all right let's make some space
00:12:31.019
and let's try to calculate the integer
00:12:33.000
that is at the midpoint between 0 and
00:12:35.459
2.1 billion
00:12:37.440
it's this number that is 1.06 billion in
00:12:40.680
decimal
00:12:41.700
we got this number by adding 0 and this
00:12:44.279
2.1 billion number and then dividing the
00:12:46.740
sum by two
00:12:48.779
this integer looks like this when we
00:12:51.120
convert it into binary
00:12:53.220
now let's take a closer look at this
00:12:55.260
binary number
00:12:56.639
and let's try to convert this integer
00:12:58.620
back into a floating Point number
00:13:01.800
the sign here is zero meaning that this
00:13:03.720
is a positive number the exponent is 127
00:13:06.959
in decimal
00:13:08.579
which means that the range starts at 2
00:13:10.320
to the power of 0 which is one and ends
00:13:12.779
at 2 to the power of 1 which is 2. and
00:13:15.180
the significant is this 4.19 Million
00:13:18.180
number in decimal
00:13:20.220
we can divide it by 2 to the power of 23
00:13:22.560
which is this 8.38 Million number and we
00:13:25.500
get 0.5 this means that we are halfway
00:13:28.560
in the range between one and two and we
00:13:31.380
can calculate this to be the number 1.5
00:13:34.139
ladies and gentlemen there we have it
00:13:36.240
1.5 is the midpoint between 0 and
00:13:38.820
infinity
00:13:40.980
all right that was a lot to take in
00:13:42.660
let's recap what we did
00:13:45.000
first
00:13:46.079
we took the floating Point endpoints of
00:13:47.940
our range which were the floating Point
00:13:49.380
numbers 0 and infinity and we read these
00:13:52.740
floating Point numbers back as integers
00:13:54.779
which were 0 and 2.1 billion as integers
00:13:58.500
remember that this process is not the
00:14:00.779
same as casting to an integer since what
00:14:03.180
we did here is we directly read the bits
00:14:05.220
of the floating Point number as if it
00:14:06.959
was an integer foreign
00:14:09.060
we then found the midpoint by adding
00:14:11.160
these two numbers and then dividing by
00:14:13.019
two it's this 1.06 billion number in as
00:14:17.760
an integer
00:14:18.959
we then read this integer midpoint back
00:14:21.660
as a floating Point number which is the
00:14:24.180
exact opposite of what we did in step
00:14:26.519
one and we were we got this floating
00:14:28.980
Point number 1.5
00:14:31.980
using this process you can show why the
00:14:34.620
very next number expected which is the
00:14:36.480
midpoint between 1.5 and infinity is
00:14:39.360
this 1.67 times 10 to the power of 154
00:14:42.839
which is a very large number
00:14:44.820
however note that Ruby uses 64-bit
00:14:47.579
floating Point numbers internally
00:14:49.800
which means that in order to calculate
00:14:51.600
this by hand you'll also have to use
00:14:53.459
64-bit floating Point numbers
00:14:55.740
instead of 32-bit floating Point numbers
00:14:57.600
like the examples shown so far
00:15:00.180
but this is left as an exercise for you
00:15:02.279
to do at home
00:15:04.260
all right now you might be asking why
00:15:06.300
does this even work why can we read
00:15:08.579
floating Point numbers as integers and
00:15:11.160
then perform binary search over it
00:15:14.160
recall that the requirements to use
00:15:16.260
binary search is that the list that is
00:15:18.300
being searched on must be either must be
00:15:20.220
sorted in either ascending or descending
00:15:22.440
order
00:15:23.699
while this reading floating Point number
00:15:25.620
is as integers guarantee that it's
00:15:27.660
sorted ascendingly in other words
00:15:30.420
does a larger floating Point number
00:15:32.160
always result in a larger integer when
00:15:35.279
that floating Point number is read as an
00:15:37.380
integer
00:15:39.360
well let's look at the parts of a
00:15:40.800
floating Point number again
00:15:42.600
the significant has 23 bits of the least
00:15:45.120
significant digits
00:15:46.920
we know that the floating Point number
00:15:48.480
with the same sign and exponent but a
00:15:50.880
larger significant will always mean a
00:15:53.160
larger floating Point number in
00:15:54.540
magnitude
00:15:55.800
and a larger significance will result in
00:15:58.320
a larger integer when we read it back as
00:16:00.480
an integer
00:16:01.740
okay so what happens when we increase
00:16:03.839
the exponent
00:16:05.639
well since the exponent determines the
00:16:07.860
range that the floating Point number is
00:16:09.660
in and since the ranges have no overlap
00:16:12.180
a larger exponent will always result in
00:16:15.360
a larger floating Point number in
00:16:17.040
magnitude
00:16:18.180
and of course this results in a larger
00:16:20.279
integer when we read it back as an
00:16:22.079
integer
00:16:23.040
therefore this satisfies the
00:16:24.839
requirements of binary search and this
00:16:26.940
is why we can use this technique to
00:16:28.620
binary search over floating Point
00:16:30.480
numbers
00:16:32.040
foreign
00:16:32.940
let's take a look at the code in Ruby
00:16:35.279
that implements the range B search
00:16:37.079
method
00:16:38.100
the code is inside the Ruby source code
00:16:40.019
which is written in C so it's
00:16:42.000
unfortunately not as easy to read or
00:16:43.980
understand as Ruby code
00:16:46.259
so I've simplified the code and parts
00:16:48.120
have been cut out for Simplicity
00:16:51.180
let's look at the function range B
00:16:53.040
search that implements the Ruby method
00:16:55.800
it accepts one argument which is the
00:16:58.680
range where binary searching over
00:17:01.019
we then get the two endpoints of the
00:17:02.940
range the beginning and the end
00:17:05.579
let's look at the case when at least one
00:17:07.860
of the two endpoints are floating Point
00:17:09.600
numbers since this is the case that we
00:17:11.579
care about
00:17:13.140
using our float value we get the C
00:17:15.660
floating point value from the Ruby float
00:17:18.000
object
00:17:19.319
the more interesting part to this line
00:17:21.059
is the call to the double as int 64
00:17:23.699
function let's take a look at the
00:17:25.740
implementation of that
00:17:27.839
we can see the implementation of it up
00:17:29.700
here
00:17:30.419
it accepts a double Precision floating
00:17:32.520
Point number and returns a 64-bit
00:17:34.799
integer
00:17:36.299
so what does this function do
00:17:38.580
it first creates this local variable
00:17:40.799
called convert which is of this type
00:17:43.140
called Union in 64 double
00:17:45.960
we can see the definition of this Union
00:17:47.820
at the top here
00:17:49.980
it's a union of either a 64-bit integer
00:17:52.500
or a double Precision floating Point
00:17:54.360
number
00:17:55.380
if you're not familiar with unions in C
00:17:57.900
it essentially lets you store any one of
00:18:00.419
these data types at the same memory
00:18:02.160
location
00:18:03.299
it's important to note that it lets you
00:18:05.160
store any one of these data types and
00:18:07.799
not all of them meaning that the size of
00:18:10.260
the Union is only as large as the size
00:18:12.419
of the largest element
00:18:14.280
in this case since both of these types
00:18:16.380
are 64 bits in size the size of this
00:18:18.720
Union is also 64 bits which is 8 bytes
00:18:22.320
let's go back to the double as in64
00:18:24.419
function
00:18:27.179
we then set the double member of the
00:18:29.100
Union
00:18:30.120
we're sending it to the absolute value
00:18:31.980
of the floating Point number using the
00:18:34.080
Fabs function
00:18:35.640
we're sending it to the absolute value
00:18:37.380
due to differences in how integers and
00:18:39.720
floating Point numbers represent
00:18:41.160
negative numbers
00:18:42.840
integers represent negative numbers
00:18:44.820
using the two's complement
00:18:47.160
whereas floating Point numbers only set
00:18:49.320
the negative bit
00:18:50.940
for example this means that for floating
00:18:53.039
Point numbers 1.5 and negative 1.5 will
00:18:56.460
only differ by a single bit which is the
00:18:58.620
sign bit
00:18:59.640
however for integers 10 and negative 10
00:19:02.580
will differ than much more than a single
00:19:04.679
bit
00:19:06.059
I won't be talking about what the two's
00:19:07.860
complemented and why integers use it
00:19:10.200
today but you can look into it if you're
00:19:12.179
interested
00:19:13.380
so in order to not worry about this
00:19:15.120
difference we use the absolute value
00:19:17.100
here
00:19:18.660
we then read the union back as an
00:19:21.120
integer and setting it to negative as
00:19:23.280
required
00:19:24.960
in the previous line we set the union
00:19:26.700
from the floating Point number and here
00:19:29.100
we read it back as an integer
00:19:31.559
note that we're doing this in order to
00:19:33.419
not perform any casting since casting
00:19:36.000
will attempt to convert the floating
00:19:38.039
Point number into an integer rather than
00:19:40.200
directly reading it as an integer
00:19:43.980
now let's go back to the range B search
00:19:46.500
function we then perform binary search
00:19:49.320
over the 64-bit integers which were read
00:19:51.600
from the floating Point endpoints
00:19:53.580
all right hopefully you followed along
00:19:55.380
and have a high level understanding of
00:19:57.360
how this code works
00:19:59.640
if you're interested in playing around
00:20:01.260
with floating Point numbers I highly
00:20:03.299
recommend this site called float.exposed
00:20:05.940
it gives you lots of useful information
00:20:07.559
about floating Point numbers
00:20:09.840
on this site you can see information
00:20:11.580
such as the floating point value
00:20:15.179
the bits that represent this starting
00:20:16.799
point number
00:20:18.179
the values of the scientists the
00:20:19.980
exponent and the significant as decimal
00:20:22.440
integers
00:20:23.940
and the value of this floating Point
00:20:25.799
number when read as a hexadecimal or
00:20:28.080
decimal integer
00:20:30.480
this talk was adapted from my blog post
00:20:32.400
at this link which you can also access
00:20:34.200
through this QR code
00:20:35.940
feel free to reach out to me through
00:20:37.320
Twitter my handle is peterz118 if you're
00:20:40.200
in the future and watching a recording
00:20:41.760
of this talk hopefully Twitter is still
00:20:43.380
alive by then
00:20:45.059
if not you can always reach out to me
00:20:47.100
through email my email is Peter pjz.ca
00:20:49.860
thank you for listening to my talk
00:21:01.919
we still have a couple of minutes if
00:21:03.600
anybody has any questions I'm uh you can
00:21:05.940
you can ask them now or you can always
00:21:07.860
talk to me after this talk I'll be
00:21:10.500
around in in the conference for the next
00:21:12.299
three days
00:21:13.679
yeah so actually
00:21:16.500
um right before this talk Benoit and I
00:21:19.740
actually looked at the implementation of
00:21:21.240
this function sir oh I need to repeat
00:21:23.880
the question
00:21:25.200
um so the question was why does
00:21:28.380
um Ruby see Ruby specifically do this uh
00:21:33.059
floating point to integer conversion
00:21:35.120
instead of
00:21:36.900
instead of just directly searching over
00:21:38.700
floating Point numbers
00:21:41.100
um and the answer is
00:21:44.159
um Benoit and I actually looked at the
00:21:46.799
implementation of this function in
00:21:48.539
truffle Ruby before this talk
00:21:50.760
and um
00:21:52.740
interestingly enough they because it's
00:21:56.340
written in Ruby it's so much more easy
00:21:59.340
to to understand in Ruby and it doesn't
00:22:02.100
do this kind of
00:22:03.900
you might call it a dirty trick
00:22:06.120
um what what they do instead is they
00:22:09.000
first check if uh if the number is
00:22:12.539
infinity and so so then so then they
00:22:15.840
know if it's infinity or not and if it's
00:22:17.700
not Infinity then they binary search
00:22:19.559
between zero and the largest floating
00:22:22.919
Point number possible and then you can
00:22:25.260
perform binary search because you can
00:22:26.760
divide the largest floating Point number
00:22:28.559
by two whereas you cannot divide
00:22:30.480
Infinity by two and so Ruby could have
00:22:33.960
done something like that but because
00:22:36.780
it's C so they wanted to do this trick
00:22:39.659
that that is very clever
00:22:42.419
um
00:22:43.080
but instead is is rather difficult to
00:22:46.020
read and um and has seemingly arbitrary
00:22:49.559
output
00:22:51.179
so so here we have Infinity right
00:22:53.100
Infinity is zero uh from the sign the
00:22:57.299
the exponent is all ones and all zero is
00:22:59.700
significant
00:23:01.080
for not a number it is
00:23:04.020
um it is also a so I have a pointer here
00:23:07.500
if you can see it um the exponents is
00:23:10.020
all ones but we have a non-zero
00:23:11.400
significant so there's actually more
00:23:13.260
than one way to denote not a number
00:23:15.960
uh in fact here there would be 2 to the
00:23:18.900
power of 23 minus 1 ways to denote not a
00:23:23.039
number
00:23:24.240
yeah so the question was why is there
00:23:26.159
eight million ways to to denote not a
00:23:28.679
number
00:23:29.400
and and the
00:23:31.200
answer to that is
00:23:33.600
um there's no
00:23:36.480
there's there's so
00:23:40.320
you you'll have to ask IEEE for that
00:23:43.500
hahaha
00:23:48.840
okay the question was do I think not a
00:23:51.419
number should be a falsy value and I'm
00:23:53.520
assuming you mean that in Ruby
00:23:56.100
uh
00:23:57.419
uh no because
00:24:00.200
falsely because this isn't JavaScript so
00:24:02.940
the only falsy value should be false in
00:24:04.740
a nil and we don't need more falsy
00:24:07.200
values
00:24:13.140
all right thank you very much