bouncer
← Back

ClojureTV · 1.6K views · 60 likes

Analysis Summary

10% Minimal Influence
mildmoderatesevere

“This is a straightforward technical talk; be aware that the presenter is an advocate for the Clojure ecosystem, which is the explicit context of the conference.”

Transparency Transparent
Human Detected
100%

Signals

The content is a live technical presentation featuring natural, unscripted speech patterns, personal professional anecdotes, and specific community interactions that are characteristic of human delivery. The transcript shows authentic linguistic disfluencies and a narrative structure based on personal experience rather than a formulaic AI script.

Natural Speech Patterns Transcript contains numerous filler words ('um', 'uh'), self-corrections ('so hang on'), and conversational asides ('if you haven't heard about that then I recommend reading the tower Manifesto').
Personal Anecdotes and Context The speaker references specific personal interactions with Alex Miller on Slack and their own professional history porting a database.
Event Provenance The video is a recording of a live technical conference (Clojure/conj 2024) with a visible speaker and audience context.

Worth Noting

Positive elements

  • This video provides an excellent, low-level explanation of how IEEE 754 floating-point numbers are structured and manipulated at the bit level in JavaScript.

Influence Dimensions

How are these scored?
About this analysis

Knowing about these techniques makes them visible, not powerless. The ones that work best on you are the ones that match beliefs you already hold.

This analysis is a tool for your own thinking — what you do with it is up to you.

Analyzed March 13, 2026 at 16:07 UTC Model google/gemini-3-flash-preview-20251217
Transcript

um I'm a an engineer at aroc uh it's an organization that does um Enterprise architecture software but that's not the topic of today um I'm going to be talking about uh A system that I built uh a couple of years ago now uh which got integrated into closure script as the math so hang on um one thing that's been bothering me here if I can great so a long time ago in a slack space Far Far Away Alex smiller announced new features um and updates that we going to be in closure 111 uh including closure. java. maath now that's a great development because it it's inconvenient to use interrupt for many common operations like mathematics but it's also very specific to the jvm and uh when you're writing crossplatform closure it could be very frustrating to be writing conditional compilation for like really common operations uh I had recently ported uh database from closure into closure script and I was running into this sort of thing all the time uh having done that once I tried to make many of my libraries uh cross compile where possible and this sort of thing where we're seeing a library which is going to be uh different on every platform where it could potentially be the same uh was a source of frustration for me so I asked Alex about it and yeah um you know a lot of the the more complex math operations like sign or tan uh logarithms these sorts of things they they have a lot of overlap between jsmath and Java Lang maath Alex said that he'd be cautious about that because there are certain numerical guarantees to these functions um and also Java math has a lot more functions than JavaScript math now they hadn't really considered in the closure C team they hadn't really considered that because portability hadn't been one of their goals but it was for me so you know what would be needed how close uh is Javascript math to what we need well if we look in JavaScript math we've got a whole uh we've got uh just a couple of constants um oh a few constants Java math only had two it's got a new one tow which uh if you haven't heard about that then I recommend reading the tower Manifesto um but the constants that we needed e and Pi are both there as well as several others um what about the functions then well JavaScript math has quite a lot of math functions in there that looks promising how does this compare to the uh Java uh Java Lang math functions okay so there's a few more here um then again the source code for all of these is generally available it's in GPL which means you can't just lift it and move it um but where did that source code come from uh turns out it comes from things with much looser licenses and So based on that probably be able to reimplement a lot of these functions in the JavaScript space but what about those guarantees that Alex was talking about um so let's see it turns out that all JavaScript numbers are floating Point numbers yes even the integers but most importantly JavaScript uses the I e754 standard for 64bit floating Point numbers uh the standard covers a couple of different uh sizes of floating Point numbers but they stick just to 64 bit but that's also exactly what Java does for its doubles so that was a really good sign um there was one caveat though the Milla Mozilla developer Network they try to provide a definitive set of document documents for the JavaScript ecosystem and they make the point that there can be variations between different implementations however I went in and started investigating with some help from other people uh on slack uh what might be involved in some of those other implementations and this caveat is more about covering your bases than uh than they being significant differences okay so I could look up those details on Wikipedia as to what the 754 standard might be or you could just buy it for 106 bucks um $83 if you're a member of i e which I am so um I've got myself a copy of the standard you can talk to me if you ever want to see it um and so I got back to him and said uh look it's using the standard format for numbers um missing a few functions but I think I can do most of it um let's see I commented the source code for the bit manipulations available in the jvm uh for instance i e remainder function uh I had started rewriting them and found that you know it seemed to be working and so Alex gave me the idea that maybe he was willing to hold off for a bit until I could go further in my investigations okay so what's involved in these numbers so the 64bit floating Point number format essentially represents numbers in scientific notation except in binary so you can see some const constants on the left there um these are uh like the gravitational constant is first and they're all physics and math constants up there uh each is expressed as a decimal number which is greater than one so one point something um and less than 10 so it's always a single um digit before the decimal point um that number is is called the mantisa and then there's an expon exponential of 10 and that basically says where that decimal point will move to will it go to the right or to the left if it's negative uh how many places will it move well the it standard does the same thing except with binary now we have a mantisa that's greater than one and less than two and an exponential of um of two which shows the uh the final placement of the well now it's called the binary point but you see how that first digit has to always be a one it can't ever be zero well they figured that they could get an extra bit for free cuz it's always going to be one why bother storing it uh so the the standard if you ever try to pull these numbers apart that that first digit is normally always missing uh there are occasions where it's not and we'll talk about that in a moment so the general structure 64 bits we have a sign bit up on the far left uh zero for POS postive one for negative we have an 11bit exponential that number is actually biased so if you see um it doesn't start at zero that has a special meaning if you see one in there that is the smallest exponential you can get and it indicates netive ,23 and then it it goes up monotonically as a any binary number all the way up to 246 um and then all ones has a special meaning as well but uh halfway in between there that indicates zero um so you know the lowest number if you see um a one in there that's going to be 2 to the ,23 if you see a um 1023 in there that means you're raising multiplying by 2 to the power of 0 which means one and uh the largest you can get in there is 1,23 okay so uh that's the the basic structure and then the mantisa is just the decimal number that I was talking about it's always shifted onto the left so uh as with decimal numbers uh once you've reached the number of decimal places accuracy you have it just runs off to zeros on the end so there are special groups in here if we start with an exponential which is all zeros in fact sorry if we have everything at all zeros except the sign bit which could still be one or zero um that is zero if the sign bit is set that means negative Z and some of you may have seen negative zeros in uh the software that you've worked with if it's floating point if the exponential is all ones that means Infinity again we've got positive and negative um however the mantisa has to be all zero as soon as a single bit in the mantisa is not a zero then instead of representing Infinity now it represents not a number you'll notice we've got with the exception of that um uh that first Manti bit we've got 51 bits of which any one of them can be one and will have a not a number value there are actually systems out there which will encode errors into there not a numbers uh if you're going to throw a a nan then uh this is what this first bit can represent uh it can indicate that we want to signal that there's an error here as opposed to let's just pass a not a number back so 0 divided by 0 you might allow that through your system but if you turn the signal on no that's got to be thrown as an exception and then finally and the one that's most of interest to me through the coming slid is the subnormal numbers um like zero our exponential is going to start at zeros um but then the rest of the number is in the mantisa this indicates that our numbers are less than negative sorry 2 to the 1022 um now these indicate very very small numbers and at this point we're going to presume that they are not preceded by a leading one now it's like a zero point and this is our number and this uh allows us to get smaller and smaller numbers because we can start with a leading string of zeros we can get smaller and smaller numbers uh all the way down to the very tiniest numbers that can be represented with this format and it's um uh and we by not having this one on the front we're treating them a little bit differently uh this group of numbers are referred to as the these subnormal numbers and yeah they cause all sorts of grief so how might that look well let's consider this number 12345 it's got this binary representation up here it's positive so first bit is zero turning it into scientific notation um just means adding a point after that first digit and the exponential is just going to say how many remaining binary digits we have um now we're going to throw away that one and that's the number we want to write into the mantisa the rest of it will be filled with zeros then it's 2 to the 13 that it's multiplied by so that gets put into the um exponential but we first have to add the bias so we get 1,36 it's that bit pattern so it goes into the exponential um that's how any number gets represented internally in both Java and JavaScript because JavaScript uses integers we're also going to have um uh sorry it doesn't use integers it pretends it uses integers uh what it does is it uses the mantisa to represent that so we can go up to um 2 to the 52 and uh that gives us our range of uh of integers that we can work in uh of course the exponent is going to say how many bits of this that we're actually using uh so there's still normal floating Point numbers except the exponent is only going to take us up to a point after which they'll be all zeros uh from there on um but this structure is what leads to the maximum safe in and the minimum safe in in Javas script if you try to go any higher or any lower then the decimal point Al sorry then uh the exponent has to go up one and there's no extra digits that we can put on the back and so we're going to lose those last bits of information and if you try incrementing up past the maximum for instance you'll suddenly see that you're jumping by two and then you'll start jumping by fours and then you'll Jump by eights and that's as the exponent continues to go up and we don't have the bits to represent the um the integer values anymore and that's why it's these are called the um the safe integer space and anything outside of that you know we can round off but we don't have accuracy anymore so how can we do bit manipulation like this in JavaScript I mean I came from C I know how to do it there well to work on it we want to slice out the high and the low double words or 32bit slices um might also want to work on the eight individual bites that make it up uh now when we're using little endian systems as we often are then these get counted from the least significant to the most to do that in JavaScript um we talk about this in a minute but it um it was very difficult to do until we started getting a buffers um so using this interface what we can do is allocate an array in this case 8 bytes to hold the double and then we can put a facade over over that buffer uh that looks like an array of 64-bit floats and another array of 32bit in now the 64-bit floats because there's only8 bytes there we're going to have a single uh single entry in that array and in the unsigned in 32 array um we've got 8 byes so we've got two of those um now we may be on a bendian system so we ask this flag of little Indian are are you set or not and we're going to set this high value to one or zero um based on that and that flag we can calculate by simply putting data into a um uh into such a buffer like this and then looking to see where it ended up okay so now I've got the uh where the the high flag is pointing to one or zero um I can now take my double put it into the the float 64 array in position zero there and now I can get out of the integer array both the high and one minus High to get the high and the low double w now um on slack Mike fights expressed some concerns about that mechanism because it's not supported on Old the browsers um David Nolan was wondering about it as well and we ended up having a long conversation and trying to figure out if we could effectively do it another way is there some other way to get to the uh to some of the bits we can definitely get to some of them but there's no effective way to pull all of them out with other sorts of operations this is the only way we figured we could do it and it has been around for a little while now and so in the end David agreed that there's no other good way to do this and it was acceptable okay so once we have these high and low words we can use typical operators to do bit manipulation sounds great except we're supposed to work on integers but JavaScript has floating Point numbers so how does that work well it turns turns out that JavaScript implicitly converts the number into a 32bit value anything larger than those 32 bits it's just thrown away so what's that look like well let's say I do an or with zero that should give me back my same number right and for a number that stays within 31 bits I do that's what I see but if I use that top 32nd bit suddenly the number isn't the same it's negative and that's because all numbers in JavaScript assigned let's say I go for an even bigger number and now it's you know I don't have that that top bit set on on for this particular number but I do um I do find that it's truncated the higher bits so I've got uh sign flipping going on I've got truncation going on it's a little bit messy um but at least we know what we're looking for here so let's go into the implementation a lot of this a lot of the functions that we want to work with don't have to worry about this uh we can just use Simple wrappers and in fact the uh closure Java math was doing exactly this so I mostly copied these functions out changed the documentation uh removed the inline uh operations that uh that that closure math now has in it um just made it a simple wrapper around the JavaScript um operations and you know this is the the Java version um but it ends up being almost the same uh in JavaScript actually no sorry this is a JavaScript version are the functions need a little more work to make it work just like Java mostly bounce checking so for instance if we're doing a rounding uh according to the Java documentation if you have uh not a number value come in you're supposed to return zero that's not how JavaScript operated so I you know dealt with that uh same thing with uh infinite numbers I had to return either uh the max safe integer or the minimum safe integer because these were the only things which are going to be uh appropriate in this case um and you know the default case I just get to call round on it again more operations which didn't seem too hard um this is getting to the point now where I don't have functions in JavaScript but I can reimplement them myself so this is for division not too hard we have to do a little bit of work pulling out um uh elements of the you know properties on the various numbers and once we know that they meet certain criteria we can um you know look for the bounds ranges of them are is one of them negative one of them positive which way does round and go that kind of thing we can implement this this ourselves and return it not uh it's relatively straightforward I got through pretty much all of these functions in the first couple of days and thinking I'm on a roll it's going to be done really quickly then I got to some trickier ones the um uh unit in last place function this one we're now really pulling apart the bits we're really looking into what's going in I'm checking up some of the other reference implementations of this to make sure that I've got it right but generally it's working out well again with all of these re-implementations took a day or two for that so I'm on a roll I'm just about done and then I hit i e remainder and it was kind of complex uh it operates the same as mod except it offers extraordinary accuracy for very small uh differences very small numbers and like looking at the implementation it's a lot uh I asked do I really need this I mean how many people really need that level of accuracy but I promised okay so where did it come from originally FD libm came from sunsoft um Sun Micro Systems uh was a part of sun micr systems it came out in 1993 it's currently hosted at the net lib math repository at University of Tennessee Knoxville and the H so um Oak Ridge National Labs so uh net lib is co-hosted by them uh it has a uh BSD style attribution license uh so you know looking at that it gave me a lot of confidence that I wasn't going to be violating any licenses if I went and started uh looking at how different people had done this because everyone had built their code over the top of that uh we find this code also in GBC uh and we find this code in the J uh jdk now when I looked at at this at the time uh it was uh it was in this path ending with eore remainder um March of last year they moved it into Java code um and in fact they've been doing this ongoing movement of Native code into Java code starting in 2015 for the whole math Library so everything in math will eventually end up there but i e remainder got there in um March of last year hadn't when I did this stuff so I'm looking at it all you know how do I how do I do this in JavaScript so looking into it this is the C code which implements it oh no not this is a very small slice of the C code that implements it uh it uses a function called f um floating point modulos and uh this is a slice out of f mod that we can see here uh there's comments there saying that it's determining the integer log binary um values for X doing various operations in uh yeah uh and it kind of looked like it was uh duplicating things here and uh it was really expanding the size of the function I figured it was probably appropriate to pull out into its own so in closure script it looks like this this is essentially a transliteration going back into i e remainder uh again we're we're looking at uh some complex code here um lots of bit shifting negations going on this sort of thing happening in here um but see these comparisons this is the low X is it less than the low Y and also down the bottom same de deal uh we're going to be doing this um uh decrement on HZ if that's HZ I'm in America sorry and um we're going to be doing the decrement if that's the case I totally didn't see this at the time just remember them for a moment so I implemented an enclosure script and it looked great I put numbers through it and I was getting exactly the same results out wonderful so then I started um running some uh uh some more testing on it and everything looked fine until I put a number in and I got something completely different come out this took a lot of debugging and I uh ended up doing uh pulling apart GBC rewriting iog B uh not sorry uh F mod and um putting print statements in there to see what it's getting out and comparing to what I'm getting out and all sorts of things happening in here and it turned out that it was these less than comparisons you'll notice that I have you less than because I had to reimplement that for myself and it's these lower order double words they're being turned into signed values and so I compare the top nibble before I then go on to to compare the remainder um you know little gotches like this were catching me out at all sorts of terms but um you know this was my final function it was my white whale I took a couple of days on it but I got it out it felt amazing so finally it's all running so I'm done right well I need to test and it had to be rigorous like people rely on math you can't just wing it so the first step was to run it all on the jvm because I mean this is jvm compatible code it should it's closure so it should just work right and I could even compare those results directly to javal Lang math uh even better I could use generative testing to compare the results of my libraries to Java Lang math um and you know that way I can't hide any indiscretions but of course some of the code doesn't just work I was making references to several JS entities so let's address those I subbed it out in a name space that I called naturally enough JS um I put in the various safe integer ranges positive Infinity you know things like this um functions like is Nan is finite is integer which I had to call they're now inclosure proper but they weren't at the time um and uh let's see is safe integer but what about those buffers that I was using for moving the this data around they look an awful lot like the nio buffers that we have in Java so generated a couple class classes to represent them and created a protocol of array access to get them using an a get and aset operation because that's how we were using arrays in closure script um so using that we can create do some Constructors up the top there where we just uh create a buffer or we use as in buffer as double buffer which is all IO operations and then um extend the protocol onto these uh classes now and we handle the um uh the signed elements like you can't put a um uh negative numbers in certain places you know we're looking for unsigned values um that we want to work with here especially for the UN 8 and the UN 32s okay so now we can do generative testing that first line D equals that was a function I had to write because sometimes a function would come back with Nan and my function would come back with Nan and they're equal right except Nan is never equal to Nan so D equals is a double equals and it considers that as well um safe integer is a range of integers that the um uh that we can operate across uh when doing generative testing just going from the minimum to the the maximum number we don't want to go out of that range because otherwise things get rounded off and it's not going to work for us uh and I can do things like here's a sign test here's a cosign test um very easy I just say four all doubles and uh the math cause is equal to the Java math cause and these things worked went great um more functions looking like this and you know this actually was how I was testing i e remainder um I thought I had it working I didn't I got it going again I thought I had it working I didn't I got it going again and this was really the the past that got me really happy and my notes here I've written I was giddy but there are some problems um this calling Java Lang math using the floor mod operation from one with this enormous number generative testing through this number at it it's supposed to come back with one but it doesn't it returns this instead um I ask in clerans and people started coming back like Adrien Smith immediately confirmed what I was seeing he pointed out yes this occurs on various jvms even what's going on well it turns out that the reflection code picks up the wrong method overload and it casts that second number into a 32-bit int now that ends up being easy to work around just by casting uh but it's a good reminder actually that I wasn't being careful about reflection um so we do unfortunately still see this in closure today this bit of code here will print whenever it gets a bad result and these are the errors we get however if we cast it nothing comes out so this is actually one of the reasons why closure math is a goodidea IDE since it'll actually ensure that people aren't accidentally reflecting okay Alex checked in with me about that time I was happy to assure him it looked good now I needed to get it into the um closure script proper so shouldn't be hard everything runs right Mike fik gets back to me and says some comments he'd been following along he had a look at it uh after the highs of that IP remainder success this kind of brought me back to Earth um but these suggestions are actually mostly about performance and they're all excellent suggestions and he was more than happy to help me out at every step he knew a lot more about the closure script system than I'd even I'd ever considered he had lots of um uh tips and tricks and and things which I could pursue to improve what I was doing a simple one was this one if you set print function bodies to be true and then you define a function then when you evaluate that function it'll print the JavaScript that was generated for it and so you can get immediate feedback what if I encode it this way versus that way you can see how this is going to look right there in your Apple you know I can't tell you how much I appreciated Mike's help during this period it was you know the things that he was suggesting to me were really valuable and I really upskilled on closure script during this time so on December 10 couple of weeks after initially starting out on this I was feeling confident enough that I made a formal request on slack about how to included enclosure script turns out that most of how to include it is documented here I am reading formal specs and forgetting to look in obvious places like javascript. org but it did inform people what I was doing so a lot more people started looking at it at this point okay so now we want to get it into JavaScript can the generative testing that I was doing earlier can that actually compare the jvm output to the JavaScript output because that would be you know ideally what I was looking for so how could I do that well step one would be to create an npple in the jvm but you can only really talk to that through strings so let's do the generative testing using strings I'm going to start out I've got a new equality function here I'm looking for um is not a number now I'm actually looking to make sure that things are numbers because sometimes they come through strings Etc uh or I could get an error an INF or something uh that the reader doesn't like um are they both the same thing coming back and equal or are they just equal so now I can do my get exp exponent test I'm going to do the the samp DS being a sequence of double values and then I can map my closure script exponent over them and map my closures get exponent over them and then if I map equality down those two sequences is every identity will tell me if anything's false but that bit cljs get exponent how do I get that to work ml bent happened to be looking online and I was saying yeah I'm thinking of setting this up couple of minutes later he posts this I was talking about maybe using a pipe he's used a socket but you know I'm not going to complain about working code that I don't have to write so now that I've got this if I put some code into it does it work it does I can eval this expression and sure enough I get back out the answer okay uh now we can generate the samples for generative testing print it to a string uh the string expression that we want to read and evaluate and compare those results to running the same jvm function over the sequence so the two sequences are then getting compared with the equality operated and checked um so you can see in my up here it's putting that sequence right in the middle now um that string you know making it look a little bit messy but it effectively ends up looking like that where we've got the sequence now embedded into our string now I've got square brackets there often times when you're generating a sequence it's going to be a list so it'll be round parenthesis hence the need for the quote okay so this is working but it's going to be very tedious to set up over and over again for all the functions that I wanted to do do it on so how might we make this a little easier to to do at scale across all the functions we need well what about macros Focus can explain why I can't tell you about macros but this is the basic structure uh this macro runs on functions take a single argument of a type hence the test T and it's and it returns a type so that's why it's t to T um so the type might be a double or it could be an integer um now the first thing the generated code does is generate that sample um it then uh does what we were looking at earlier where we emit the numbers convert to doubles then we map the expressions of Interest over them and so you'll see the uh cmfn uh was the closure script function that we want to map over it um that's just getting spliced in um we're going to do the same mapping over the sequence in Java and finally We compare it all so now that we've got that we can start expanding it out and uh now we can start building more macros over it so like test double to double or test function that takes two doubles and returns a double and we build this o over the previous macros that we have and so there's a few different variations in there now I'm not showing them all so then we get to R write nice simple expressions like this and it executes equivalent operations on the jvm and a closure script repple and there's several variants here including comparisons that can print what's going on with values are close but not equal uh or operations that can't take zeros for some arguments like the uh Flor uh floor div you can't divide by zero that sort of thing and so uh with all of that going now I'm feeling more confident so I I explained everything to David we had a number of conversations um he approved and David's standards are so high that getting something approved by him was almost as good as getting i e remained at work so I learned how to follow the formal patch process it's on the website if anyone wants to do this um created an appropriate J ticket attached the patch then David said he merched it and a handful of people said they liked me [Applause] so then we had um to wait he hadn't made the next release yet and I was getting impatient but if you recall in Alex's original announcement there were a whole lot of new functions coming out and they weren't in closure script yet so I went and did those because what else am I going to do while I'm waiting and then it got released um this was about six months after I started the process some of that was just waiting some of that was getting feedback from people um the original tough part of the coding literally took five days 95% of the work was not the coding it was working with the people involved it was going through the community process it was making friends and uh having people help me at every step of the way learning how to integrate in with the larger ecosystem um it's somewhat belated but I want to say a special thank you to everyone who helped me helped me to get it done Alex Miller for being willing to hear me out and changing the name from closure. java. maath to closure. maath Mike Fikes for his friendship and thorough evaluations along with patient and knowledgeable explanations David noan for his advice and willingness to work on this with me nichel bent for saving me a couple of days work when I really needed it and everybody who interacted with me over slack with comments suggestions or encouragement for what I was doing um it helps motivate you when the community likes to see what you're doing um and so I just want to say thank you to all you out there [Applause]

Video description

This talk explores the implementation of Java's math functions in ClojureScript, aiming for functional parity with Clojure's math operations. We'll examine the intricacies of IEEE 754 floating-point operations, the challenges of bitwise operations in JavaScript, and approaches for thorough cross-environment testing. The presentation will cover how low-level mathematical operations can be implemented in ClojureScript, and the insights gained about the compiler and ecosystem. The talk will also highlight the collaborative process with ClojureScript maintainers, providing a look at contributing to a core language project. This presentation offers perspectives on language internals, precise numerical computations, testing techniques, and the community-driven nature of open-source development. Recorded Oct 24, 2024 at Clojure/conj 2024 in Alexandria, VA

© 2026 GrayBeam Technology Privacy v0.1.0 · ac93850 · 2026-04-03 22:43 UTC