[HN Gopher] 4 billion if statements (2023)
       ___________________________________________________________________
        
       4 billion if statements (2023)
        
       Author : damethos
       Score  : 553 points
       Date   : 2025-12-06 15:34 UTC (6 days ago)
        
 (HTM) web link (andreasjhkarlsson.github.io)
 (TXT) w3m dump (andreasjhkarlsson.github.io)
        
       | thewisenerd wrote:
       | discussed 2 years ago,
       | 
       | https://news.ycombinator.com/item?id=38790597
       | 
       | 4B If Statements (469 comments)
        
         | unwind wrote:
         | Meta: Yeah, this should have a "(2023)" tag in the title.
         | Thanks.
        
       | SiempreViernes wrote:
       | > As a side note, the program is amazingly performant. For small
       | numbers the results are instantaneous and for the large number
       | close to the 2^32 limit the result is still returned in around 10
       | seconds.
       | 
       | Amazing!
        
         | tanseydavid wrote:
         | This line from the article -- I will be laughing about it for
         | days.
        
       | isoprophlex wrote:
       | > Visionary genius Ross van der Gussom
       | 
       | Thanks for making me doubt myself & googling who that guy who
       | made python was again, because surely "van der Gussom" isn't a
       | normal Dutch name. Well played.
        
         | mcny wrote:
         | Previously on HN
         | 
         | https://news.ycombinator.com/item?id=38790754
        
       | d-lisp wrote:
       | if(n&1)
       | 
       | else
        
         | imtringued wrote:
         | You can do it even faster with the if statements:
         | #include <stdio.h>         #include <stdlib.h>              int
         | main(int argc, char *argv[])         {             if (argc <
         | 2) {                 fprintf(stderr, "Usage: %s <string>\n",
         | argv[0]);                 return 1;             }
         | char *s = argv[1];             int i;                  /* find
         | the end of the string */             for (i = 0; s[i] != '\0';
         | ++i)                 ;                  /* make sure the string
         | wasn't empty */             if (i == 0) {
         | fprintf(stderr, "Error: empty string\n");
         | return 1;             }                  /* last character is
         | at s[i - 1] */             char d = s[i - 1];
         | if (d == '0')                 printf("even\n");             if
         | (d == '1')                 printf("odd\n");             if (d
         | == '2')                 printf("even\n");             if (d ==
         | '3')                 printf("odd\n");             if (d == '4')
         | printf("even\n");             if (d == '5')
         | printf("odd\n");             if (d == '6')
         | printf("even\n");             if (d == '7')
         | printf("odd\n");             if (d == '8')
         | printf("even\n");             if (d == '9')
         | printf("odd\n");                      return 0;         }
         | 
         | gcc -std=c11 -Wall -Wextra -O2 -o check_digit check_digit.c
         | 
         | ./check_digit 9999999999999999999999999999999999999999999999999
         | 999999999999999999999999999999999999999999999999999999999999999
         | 999999999999999999999999999999999999999999999999999999999999999
         | 999999999999999999999999999999999999999999999999999999999999999
         | 999999999999999999999999999999999999999999999999999999999999999
         | 999999999999999999999999999999999999999999999999999999999999999
         | 99999999999999999999999999999999
        
           | Tistron wrote:
           | You can do it even even faster by replacing your if
           | statements (works because the ascii values end in the digit
           | they represent):                   if (d & 1)
           | printf("odd\n");         else             printf("even\n")
        
           | wiz21c wrote:
           | I'm disappointed, it's not in rust. :-)
        
             | actionfromafar wrote:
             | Still hoping for the C++ template version. Don't pay for
             | what you don't use!
        
           | tetris11 wrote:
           | probably easier in bash:                   number="$1"
           | if [[ "$number" =~ "^(2|4|6|8|10|12|14|16|18|20)$" ]]; then
           | echo even         elif [[ "$number" =~
           | "^(1|3|5|7|9|11|13|15|17|19)$" ]]; then             echo odd
           | else             echo Nan         fi
           | 
           | A bit limited, but you can scale it up
        
           | d-lisp wrote:
           | You inspired me this joyful rewrite:
           | #define _(e) { e;};         #define r(e) _(return e)
           | #define I(b, e) _(if (b) r(e));         #define W(e) _(while
           | (1) _(e));         int main(int c, char **v) {
           | _(I(c != 2, -1) _(c = 0) W(I(!v[1][c++], v[1][c - 2] & 1)))
           | }
        
       | tigranbs wrote:
       | This reminds me of my personal "prime number" grabber research
       | https://github.com/tigranbs/prime-numbers I needed to create the
       | unique graph nodes and assign prime numbers, and to make things
       | efficient, I thought, why not just download the list of known
       | prime numbers instead of generating them one by one. So I did and
       | compiled everything with a single Go binary. Ehh, good old days
       | with a nice feith in making "the best" crappy software out there.
        
       | wiz21c wrote:
       | Gemini took 4 seconds to answer this prompt: "Here is a number
       | 4200020010101. Think deeply about it and tell me if it is not or
       | or not even."
       | 
       | So if you're concerned with privacy issues, you can run the
       | assembly version proposed in the article _locally_ and be well
       | within the same order of performance.
       | 
       | Let's thank the author of the article for providing a decent
       | alternative to Google.
       | 
       | ah, but the license is not that good we can't reproduce his code.
        
         | brap wrote:
         | >Think deeply about it and tell me if it is not or or not even
         | 
         | I think I just experienced a segfault
        
           | bdangubic wrote:
           | +1
        
             | rossant wrote:
             | Nice, that swaps odd and even around.
        
           | sethaurus wrote:
           | Why do they call it even when you of in the true number of
           | out false odd the number?
        
             | pksebben wrote:
             | Has anyone really been far even as decided to use even go
             | want to do Look more like?
        
           | iberator wrote:
           | Hey, why segfault and not stack overflow?
        
         | classified wrote:
         | > if it is not or or not even
         | 
         | Did you want to test the LLM's grammatical comprehension?
        
           | wiz21c wrote:
           | When I'm tired my typing goes bad. I obvioulsy meant: "is
           | that number even odd ?" :-)
        
         | moffkalast wrote:
         | Finally a problem that Microsoft Phi can ace. Probably. Maybe.
         | Some of the time at least.
        
           | kspacewalk2 wrote:
           | Surely you mean Microsoft CoPhiLot 365
        
       | orzig wrote:
       | If the author is available for consulting I have this bag of rice
       | I need cooked. Should be around 30,000 grains, each needs about
       | 1mL of water and 2m on the stove. Will pay $10 (2025 dollars)
        
         | franciscop wrote:
         | Aha, you forgot to specify the country of those "dollars"! For
         | $10 (2025 [Cayman Islands] dollars)! Which is higher than USD10
        
           | 867-5309 wrote:
           | Zimbabwe: 0.027 USD
        
       | xg15 wrote:
       | > _Now, this is a time-memory tradeoff, but my time on this earth
       | is limited so I decided to meta-program the if statements using a
       | programmer program in a different programming language._
       | for i in range(2*8):         if i % 2 == 0:
       | 
       | No comment...
        
         | cowsandmilk wrote:
         | How horridly inefficient, he should have just flipped a Boolean
         | on each iteration.
        
           | kroolik wrote:
           | Horridly inefficient. Just unfold the loop.
        
           | projektfu wrote:
           | Just output odd and even for each pass and increment by two.
           | Need to make sure you have the right starting value, and
           | check for off-by-one errors.
        
         | _ache_ wrote:
         | Yeah... I come here to talk about that. Should have been
         | for i in range(0, 2**8, 2):           print("    if (number ==
         | "+str(i)+")")           print("        printf(\"even\\n\");")
         | print("    if (number == "+str(i + 1)+")")           print("
         | printf(\"odd\\n\");")
         | 
         | or                 for i in range(0, 2**8, 2):
         | print(f"""    if (number == {i})               puts("even");
         | if (number == {i + 1})               puts("odd");""")
        
           | NetMageSCW wrote:
           | What happens when you try to compute 2**8+1 ?
        
             | iberator wrote:
             | Should work fine with long long?
        
             | amoss wrote:
             | If its too large you could just subtract 2*8 and try again.
        
         | PurpleRamen wrote:
         | I think we can improve this. Just make a microservice who
         | generates the code on the fly and streams it to the compiler.
         | Then you also just have to create the necessary code and don't
         | waste the SSD with unused code-paths.
        
           | travisgriggs wrote:
           | I'm disappointed there is no docker image for this. How will
           | I test it out?
        
             | PurpleRamen wrote:
             | Microservice kinda implies usage of a container for me. How
             | else would we google-scale it to serve all requests in
             | parallel?
             | 
             | But thinking about, we probably have to use some more
             | microservices, we can't put all that burden on the
             | requester. So a dedicated service for compiling and
             | executing in sandboxes would be necessary. Also, some local
             | load balancers to control the flow and filter out the
             | useless answers. So I'm not an expert on that devops-magic,
             | but I guess this means ~12.5 billion pods fast enough
             | result. Do Amazon or Google offer planetary scale for
             | services?
        
         | layer8 wrote:
         | It should have used a flag that is being toggled.
        
         | catigula wrote:
         | Claude's version:                 even, odd = "even", "odd"
         | for i in range(2\*32):           print(f'    if (number == {i})
         | puts("{even}");')           even, odd = odd, even
         | 
         | As usual, a non-marginally superior mind to commentators.
        
       | wvbdmp wrote:
       | Next put them in a tree for faster lookups.
        
         | wiz21c wrote:
         | With a tree you'll be limited by the RAM. I advise to use a
         | database.
        
           | actionfromafar wrote:
           | Map reduce, cluster geo-failover and CDN caching for
           | optimized coldstarts in case you have to bring it up from
           | scratch in a new datacenter. Bio for contact info, hourly
           | billing. I have helped many startups reach their first
           | 100MARR. Buy my audiobook.
        
           | roguecoder wrote:
           | Don't forget to create an index on the composite key [number,
           | is_even]!
        
         | d--b wrote:
         | Don't reinvent the wheel, put them in a SQLite table, and let
         | the sql engine create the tree for you!
        
       | ZeroConcerns wrote:
       | Ah, yes, exactly the pointless diversion I needed for my lunch
       | break. For science: generating a C# switch statement for similar
       | purposes took 7 minutes on similar-ish hardware, but the
       | resulting 99.2GB file could not be opened or compiled ('Stream is
       | too long'), which was slightly disappointing.
       | 
       | Optimization efforts included increasing the internal buffer size
       | of the StreamWriter used to create the source code: this reduced
       | the runtime to around 6 minutes, as well as running a non-debug
       | build, as it was observed that the poor Visual Studio metrics
       | gathering process was contributing significantly to disk activity
       | as well, but that ultimately didn't matter much. So, ehhm, yes,
       | good job on that I guess?
        
         | afandian wrote:
         | Isn't the obvious thing to generate different classes for
         | different ranges over the input? Then the classes could be
         | loaded lazily.
         | 
         | And if you then make the ranges tree-shaped you get logarithmic
         | complexity, which massively cuts down the O(n) of the rather
         | naive chained `if` statements.
        
         | opticfluorine wrote:
         | I wonder if you could generate it via a Roslyn incremental
         | source generator instead of as a file to bypass this limit. I'm
         | guessing not, but it does sound like fun.
        
           | tkapin wrote:
           | You can totally use source generators for that.
        
             | xnorswap wrote:
             | You're only allowed up to 65535 locals, but this includes
             | hidden locals, which the compiler adds if you're compiling
             | in debug mode.
             | 
             | So you have to make sure to compile only in release mode
             | just to get to 16 bits.
        
         | jiggawatts wrote:
         | To match the article, you'd want to directly emit the
         | Intermediate Language (IL) tokens with something like this:
         | https://learn.microsoft.com/en-us/dotnet/api/system.reflecti...
         | 
         | I haven't found any authoritative source, but I strongly
         | suspect that the .NET bytecode format has 32-bit limits all
         | over the place. Maaaybe you could break up the code into
         | functions less than 1 GB in size and then chain them together.
        
       | whynotmaybe wrote:
       | > I decided to implement this in the C programming language as
       | it's by far the fastest language on the planet to this day
       | (thanks to the visionary genius Dennis Richie)
       | 
       | Am I lost? Aren't the compiler/linker responsible for fast code,
       | not the language itself?
        
         | croes wrote:
         | People often use language as synonym for the whole ecosystem
         | including compiler and linker
        
         | reedf1 wrote:
         | It's a wild statement for a few reasons; your observation is
         | one of them.
        
         | mbivert wrote:
         | > I decided to use the slowest language on the planet, Python
         | (thanks to the visionary genius of Ross van der Gussom).
         | 
         | given the article, it's fair to assume the author was joking
         | around
         | 
         | that being said, the way the language is used and its ecosystem
         | do contribute to the executable's efficiency. yet, given C's
         | frugality, or the proximity between its instructions and the
         | executed ones, it's not unfair to say that "C is fast"
        
         | rcxdude wrote:
         | Both, usually. A language's semantics can limit how much a
         | compiler can speed up the language. Python, for example, is
         | extremely difficult to make fast due to the fact that almost
         | everything has the semantics of a hashmap lookup. C, in
         | comparison, has relatively little in it that can't be mapped
         | fairly straightforwardly to assembly, and then most of it can
         | be mapped in a more difficult way to faster assembly.
        
         | bluGill wrote:
         | There are language issues as well. 99% of C programs are valid
         | C++, and if you compile with a C++ compiler instead of a C++
         | compiler will be slightly faster! C++ ha a stronger type system
         | and so once in a while (very rarely) those C programs compile
         | but give incorrect results since C++ allowed the optimizer to
         | make an assumption that wasn't true. Fortran is often even
         | faster because the language allows for even more assumptions. I
         | don't know where Rust fits in here (Rust is hurt today because
         | the better optimizes are designed for C++ and so don't take
         | advantage of extra assumptions Rust allows - it was designed to
         | allow different assumptions from C++ and likely could be better
         | would a ground up optimizer but that would take a large team a
         | decade+ to write: expensive)
         | 
         | Most of the difference in speed is the optimizer/linker.
         | Assuming a fair competition the difference between Ada, C, C++,
         | D, Fortran, Rust, Zig (and many others I can't think of) is
         | very rarely even 1% in any real world situation. Of course it
         | isn't hard add pessimization to make any language lose,
         | sometimes accidentally, so fair competitions are very hard to
         | find/make.
         | 
         | Then again, the article was clearly sarcastic.
        
       | KeplerBoy wrote:
       | kind of expected gcc to see right through the 300 gigs of code
       | and compile it down to the tenish instructions.
        
         | bspammer wrote:
         | They disabled optimisations:
         | 
         | > Lets compile the code, disabling optimizations with /Od to
         | make sure that the pesky compiler doesn't interfere with our
         | algorithm
        
           | bluGill wrote:
           | I would have wanted to see them look at the assembly from
           | various optimization levels to see if the compiler really
           | did. Ideally o1 or something wouldn't see through this but
           | would generate better code in other ways. Disabled
           | optimizations often are really stupid about how they code
           | gen.
        
         | oneeyedpigeon wrote:
         | > disabling optimizations with /Od
         | 
         | And that weird flag is because it's a windows compiler: cl.exe,
         | not gcc.
        
         | encom wrote:
         | I'm curious what GCC would do if it wasn't purposely
         | lobotomised and fed 300 GB of this nuclear waste.
        
           | encom wrote:
           | Well I created the 16 bit .c file, because I'm not _that_
           | curious. gcc -O0 completed immediately and made a 1,5MB
           | executable. -O1 took about 10 minutes for a 1,8 MB
           | executable. -O2 has been running for 1h15m so far...
           | i7-14700K
           | 
           | I'm in too deep now, so I'll let it run while I'm at work.
        
             | KeplerBoy wrote:
             | Keep us updated.
        
               | encom wrote:
               | GCC -O2 made a 1,8 MB executable after a bit over four
               | hours. I'm not trying -O3 :D
               | 
               | I don't know enough about compilers to answer why this
               | doesn't get optimised down to something tiny, or why it
               | took so long. I'm not sure what we've learned tonight,
               | but there you go.
        
       | philippta wrote:
       | > I saw from the SSD was around 800 MB/s (which doesn't really
       | make sense as that should give execution speeds at 40+ seconds,
       | but computers are magical so who knows what is going on).
       | 
       | If anyone knows what's actually going on, please do tell.
        
         | ricardo81 wrote:
         | Presumably after the first run much or all of the program is
         | paged into OS memory
        
           | tomtomtom777 wrote:
           | Yes, or it was still in memory from writing.
           | 
           | The numbers match quite nicely. 40gb program size minus 32gb
           | RAM is 8gb, divided by 800mb/s makes 10 seconds.
        
         | hellzbellz123 wrote:
         | I'm not entirely sure but could it be predictive branching?
        
       | jagged-chisel wrote:
       | I have never seen anyone argue for a 'switch' version.
       | switch (v) {          case: 0,2,4,8,...:            return EVEN;
       | case: 1,3,5,7,...:            return ODD;          default:
       | return IDK;         }
       | 
       | Slightly less code to generate.
        
         | willguest wrote:
         | you forgot the logic to strip the final digit and assign it to
         | v.
         | 
         | processing the whole number is absurd
        
           | pkaeding wrote:
           | I think the idea is to fill in the ellipses with even/odd
           | numbers, up to 4B.
           | 
           | You know, to save the performance cost of processing the
           | input as a string, and chomping off all but the last
           | character.
        
           | 71bw wrote:
           | Look at Mr. Rocket Scientist over here...
        
           | mgaunard wrote:
           | Converting to decimal is just as absurd.
           | 
           | All you need is the final binary digit, which incidentally is
           | the most optimal codegen, `v & 1`.
        
       | oneeyedpigeon wrote:
       | I prefer data-driven programming, so a simple:
       | return odd_or_evenness[n];
       | 
       | works for me, alongside a pretty big array.
        
         | projektfu wrote:
         | You might like the IBM 1620.
         | 
         | https://en.wikipedia.org/wiki/IBM_1620#Anecdotes
        
         | enopod_ wrote:
         | This is the way.
        
         | layer8 wrote:
         | With data-driven programming, I would have expected an SQL
         | table containing all the precomputed results. Unless you
         | carelessly add an index, it has the same asymptotic
         | performance!
        
         | Zambyte wrote:
         | const odd_or_evenness = comptime blk: {             var buf:
         | [16]bool = undefined;             var is_even = false;
         | for (&buf) |*b| {                 b.* = is_even;
         | is_even = !is_even;             }             break :blk buf;
         | };
         | 
         | This looks like a promising strategy.
        
       | 1a527dd5 wrote:
       | I love "stupid" stuff like this; you normally learn something
       | small and seemingly inane. It's fun!
        
       | shevy-java wrote:
       | Damn it - my code got leaked!
        
       | mft_ wrote:
       | Similar humour if opposite directions to an old favourite:
       | https://joelgrus.com/2016/05/23/fizz-buzz-in-tensorflow/
        
         | thih9 wrote:
         | I expected some job interview meme[1][2] but I did not know
         | this one and it looks like a real story too! Thanks for
         | sharing, that was a fun read.
         | 
         | [1]: https://aphyr.com/posts/342-typing-the-technical-interview
         | 
         | [2]: https://www.richard-towers.com/2023/03/11/typescripting-
         | the-...
        
           | waisbrot wrote:
           | I love the Aphyr posts.
           | 
           | > "Can I use any language?" > > "Sure." > > Move quickly,
           | before he realizes his mistake.
        
       | tornadofart wrote:
       | "The executable is around 2 MB"- Every dotnet programmer: "Those
       | are rookie numbers!"
        
       | mgaunard wrote:
       | A much cooler approach would have been to generate the ASM from
       | the same program, rather than generate a file from python and
       | load that file from C++. The multi-stage build and filesystem are
       | completely unnecessary.
       | 
       | The technique actually has a lot of practical applications, so
       | it's useful to have a C++ library that helps you with generating
       | amd64 machine code.
        
       | tomaskafka wrote:
       | Oh, I have an idea for better leftpad implementation, let me
       | publish that to npm real quick!
        
       | ajsnigrutin wrote:
       | Why not optimize this? Create a lookup table, a 2^64 large array
       | of bools, and just check the n-th element to see if it's odd or
       | even?
       | 
       | Many gigabytes saved!
       | 
       | /s
        
       | DeathArrow wrote:
       | I would also like to praise the visionary genius Ross van der
       | Gussom, without whom this wonderful achievement in software
       | engineering would not have been possible!
        
         | klaff wrote:
         | Is he the one married to the singer, Adele Dazeem?
        
           | DeathArrow wrote:
           | No, this one is the creator of the mighty programming
           | language Mython.
        
       | blauditore wrote:
       | This could be obviously done with much less code: Just add "if"s
       | for all even number, and at the end just return "odd" if none of
       | the evens matched. 50% less code!
       | 
       | Or even simpler: If it's 0, return "even". If not, do a recursive
       | call to n-1, if that equals "even", return "odd", otherwise
       | return "even".
       | 
       | But the best way is probably to just use a library. Yes, 500MB of
       | additional dependencies, but then it's a one-liner.
        
         | layer8 wrote:
         | You could save stack space by transforming it into a loop. It's
         | still only O( _n_ )!
        
         | majkinetor wrote:
         | But then, even numbers will have the worst possible
         | performance.
        
           | IncreasePosts wrote:
           | Good point. Have two programs - one checking every even
           | number and returning odd of not even. And then have a program
           | checking every odd number and returning even if not. Then, a
           | simple program to dispatch to either program randomly, so you
           | end up in the long term with good performance for each.
        
             | rdiddly wrote:
             | Yeeessss! Microservices!
        
               | chihuahua wrote:
               | Your mention of Microservices opened up my mind to
               | additional possibilities. How about we create a
               | microservice for each integer, then deploy 4 billion of
               | them. Send a request to all of them simultaneously. Only
               | one of them will respond with the answer. We still need
               | to decide how to deploy those microservices - one per
               | machine, or multiple per machine?
        
             | hybridtupel wrote:
             | Why not run both and use the result retrieved the fastest.
        
           | bobbylarrybobby wrote:
           | You brought up an important opportunity for optimization. If
           | you know the distribution of your data, it may make more
           | sense to implement it in terms of the odd numbers and leave
           | even numbers as the fallback. It's important to profile with
           | a realistic distribution of data to make sure you're
           | targeting the correct parity of numbers.
        
       | ks2048 wrote:
       | Silly. Don't waste your time on problems other people have
       | already solved! Use JS and "npm install odd_or_even".
        
       | layer8 wrote:
       | This is also a nice approach for FizzBuzz in leetcode interviews.
       | 
       | Moreover, interviewers will be smitten by the hand-optimized
       | assembly code.
        
       | nmilo wrote:
       | I see why now npm's is-odd has millions of downloads
        
       | mring33621 wrote:
       | I recently asked a Qwen model to write me some code to remove
       | errant spaces ("c he es e" instead of "cheese") in OCR'd text. It
       | proceeded to write 'if' blocks for every combo of all English
       | words and all possible errant spaces. I did not wait for it to
       | finish...
        
       | riwsky wrote:
       | Would be more maintainable if they injected the loading strategy
       | to be used as a dependency from config instead of hardcoding it
       | :/
        
       | travisgriggs wrote:
       | I see this is 2023... the article refs GPT even then. Can't
       | believe it's already that much time gone by, still seems like
       | "last years big news"
       | 
       | I was gonna comment "this is what I really like to see on HN".
       | Then I saw the date and was sad that we're having to dip into the
       | history box to find fun/interesting articles more often of late
       | it seems.
       | 
       | Anyone else interested in a temporary moratorium on all things
       | LLM? We could have GPT-free-Wednesday, or something like that :)
        
         | LPisGood wrote:
         | > Then I saw the date and was sad that we're having to dip into
         | the history box to find fun/interesting articles more often of
         | late it seems
         | 
         | We don't _have_ to. You could start a blog and display the
         | indomitable human spirit.
        
         | virgilp wrote:
         | Definitely not a visionary. This is how you do it in 2025:
         | https://imgur.com/rWiP90P
        
         | bigstrat2003 wrote:
         | > Anyone else interested in a temporary moratorium on all
         | things LLM? We could have GPT-free-Wednesday, or something like
         | that :)
         | 
         | I would be interested in a permanent moratorium, personally.
         | There's no interesting content to be had in the various LLM
         | articles that litter HN these days. Or failing a topic ban, at
         | least give a way to filter it for those of us who are sick of
         | hearing about AI hype.
        
       | xnorswap wrote:
       | This is time efficient* but rather wasteful of space.
       | 
       | The best way to save space is to use a Bloom Filter.
       | 
       | If we capture all the even numbers, that would sadly only give us
       | "Definitely not Even" or "Maybe Even".
       | 
       | But for just the cost of doubling our space, we can use two Bloom
       | filters!
       | 
       | So we can construct one bloom filter capturing even numbers, and
       | another bloom filter capturing odd numbers.
       | 
       | Now we have "Definitely not Even" and "Maybe Even" but also
       | "Definitely not Odd" and "Maybe Odd".
       | 
       | In this manner, we can use the "evens" filter to find the odd
       | numbers and the "odds" filter to find the even numbers.
       | 
       | Having done this, we'll be left with just a handful of unlucky
       | numbers that are recorded as both "Maybe even" and "Maybe odd".
       | These will surely be few enough in number that we can special
       | case these in our if/else block.
       | 
       | The filters as a first-pass will save gigabytes of memory!
        
         | nixpulvis wrote:
         | How is this time efficient at all? It takes upwards of 40
         | seconds to compute on large 32bit values.
         | 
         | It's a joke post with some interesting bits and details.
        
           | xnorswap wrote:
           | It's a constant number of lookups, and all good Computer
           | Scientists know that it is therefore an O(1) algorithm.
           | 
           | It is hard to imagine better efficiency than O(1)!
           | 
           | Indeed we could improve it further by performing all
           | evaluations even when we find the answer earlier, ensuring it
           | is a true Constant Time algorithm, safe for use in
           | cryptography.
        
             | nixpulvis wrote:
             | > This is time efficient* but rather wasteful of space.
             | 
             | You're saying that the blog's solution is time efficient.
             | Which it is not. Your solution may be O(1) but it is also
             | not efficient. As I'm sure you are aware.
             | 
             | I can tell you a practical solution which is also O(1) and
             | takes up maybe 2 or 3 instructions of program code and no
             | extra memory at all.
             | 
             | `x & 1` or `x % 2 != 0`
             | 
             | This blog post was taking a joke and running with it. And
             | your comment is in that spirit as well, I just wanted to
             | point out that it's by no means time efficient when we have
             | 2s or 1s complement numbers which make this algorithm
             | trivial.
        
               | icambron wrote:
               | You need to read their entire comment as a joke.
        
               | nixpulvis wrote:
               | I guess I should have been more clear that I was just
               | pointing out the obvious in case some confused reader
               | missed the joke.
               | 
               | lol
        
               | ricardo81 wrote:
               | explaining the joke spoils the joke, such is social
               | convention.
        
               | nixpulvis wrote:
               | Forgive me for not being funny.
        
               | kbelder wrote:
               | Which was also obvious, but maybe also needed pointing
               | out, which says _something_ about online discussion.
               | Something obvious, probably.
        
               | henrikschroder wrote:
               | > I just wanted to point out that
               | 
               | We already know. Everybody knows. That's the joke.
               | There's no need to point out anything.
        
           | Maxatar wrote:
           | The comment you're replying to is also a joke, with some
           | interesting bits and details.
        
             | nixpulvis wrote:
             | I think I'll just avoid commenting on jokes from now on.
        
           | Sohcahtoa82 wrote:
           | How are you able to recognize a joke post but not a joke
           | comment?
        
             | nixpulvis wrote:
             | I may have missed the * meaning. I got that the bloom
             | filter was an extension of the joke as I mentioned below. I
             | was just clarifying in case someone else missed the joke.
        
           | uplifter wrote:
           | You're absolutely right. The obvious solution would have been
           | to create a boolean table containing all the pre-computed
           | answers, and then simply use the integer you are testing as
           | the index of the correct answer in memory. Now your isEven
           | code is just a simple array lookup! Such an obvious
           | improvement, I can't believe the OP didn't see it.
           | 
           | And with a little extra work you can shrink the whole table's
           | size in memory by a factor of eight, but I'll leave that as
           | an exercise for the interested reader.
        
             | mandarax8 wrote:
             | Maybe we can even find some correlation in the bit pattern
             | of the input and the Boolean table!
        
             | jiggawatts wrote:
             | If the "exercise" is to strictly rely on if-else
             | statements, then the obvious speedup is to perform a binary
             | search instead of a linear one. The result would still be
             | horrifically space inefficient, but the speed would be
             | roughly the time it takes to load 32x 4KB pages randomly
             | from disk (the article memory-mapped the file). On a modern
             | SSD a random read is 20 microseconds, so that's less than a
             | millisecond for an even/odd check!
             | 
             |  _" That's good enough, ship it to production. We'll
             | optimise it later."_
        
           | nrhrjrjrjtntbt wrote:
           | r/whoosh
        
         | gopalv wrote:
         | > But for just the cost of doubling our space, we can use two
         | Bloom filters!
         | 
         | We can optimize the hash function to make it more space
         | efficient.
         | 
         | Instead of using remainders to locate filter positions, we can
         | use a mersenne prime number mask (like say 31), but in this
         | case I have a feeling the best hash function to use would be to
         | mask with (2^1)-1.
        
           | AlotOfReading wrote:
           | This produced strange results on my ternary computer. I had
           | to use a recursive popcnt instead.
        
             | piersadrian wrote:
             | this is my new favorite comment on this cursed website
        
       | nonethewiser wrote:
       | Configuration over logic. At a new scale enabled by AI.
        
       | thedougd wrote:
       | I took an ASIC design class in college, unfortunately with a
       | heavy course load that didn't allow me to focus on it. For our
       | final project we were given a numbered dictionary and asked to
       | design a chip that would accept the characters on a 7 bit
       | interface (ASCII), one character per clock cycle and output the
       | dictionary number on an output interface but I can't remember how
       | wide. We were graded on the size of the resulting ASIC and how
       | many clock cycles it took from the last character in to the
       | number on the output.
       | 
       | I started designing my modules, a ROM, a register with a ROM
       | pointer, etc, etc, writing the Verilog and working out the clock
       | sync between modules. Then I got 'lazy' and wrote a trie tree
       | like implementation in Java, and have it spit out the whole tree
       | in Verilog. It worked and just one clock cycle after the last
       | letter my number would output. Fastest in the class! Also the
       | most number of gates in the class. Surprised I got a 90 grade
       | given I didn't use any of the advanced ASIC design the class
       | taught. The TA didn't know what the hell they were looking at.
        
         | weli wrote:
         | Yep! Something a bit counterintuitive on circuit design is that
         | dedicated transistors will always beat reusing existing
         | components. If we do reuse existing components like ALUs,
         | multipliers, or state machines, we save on chip area but pay
         | the penalty in clock cycles. Your approach was the extreme
         | version of this tradeoff. You essentially unrolled the entire
         | dictionary lookup into pure combinatorial logic (well, with
         | registers for the input characters). One clock cycle latency
         | because you weren't doing any sequential searching, comparing,
         | or state machine transitions just racing electrons through
         | logic gates.
        
           | retrac wrote:
           | It's akin to a compiler unrolling a loop. Uses more RAM
           | (area) but fewer cycles to execute. Hardware synthesis uses
           | many of the same techniques as compilers use to optimize
           | code.
           | 
           | It's a common pitfall for those learning hardware description
           | languages like Verilog, when they think about them like
           | programming languages. If you go "if (calc) res <= a * b;" If
           | res is 32 bits wide then you have instantiated a 32 bit fast
           | multiplier circuit dedicated just to that one operation. This
           | is often not what was intended.
           | 
           | Despite how leaning on the analogy too closely can mislead in
           | that way, the analogy between hardware and software is not a
           | shallow one. A combinatorial circuit is akin to the pure
           | function of functional programming. Anything that can be
           | described as a pure function working on fixed integers or
           | floating point or other discrete data types, can be
           | transformed into a combinatorial circuit. And there are
           | algorithms to do so automatically and often with reasonable
           | efficiency.
           | 
           | Free software synthesis has come a long way in recent years,
           | by the way. There's even several hobbyist projects that can
           | take VHDL or Verilog and produce layouts using TTL chips or
           | even discrete transistor logic with automatic circuit board
           | layout. You can now compile your code directly to circuit
           | board copper masks and a part list.
        
       | kayge wrote:
       | > any value over 2^31 seems to give random results.
       | 
       | Wow he really lucked out... On his way to perfecting a fully
       | functioning and performant Even/Odd Detector, he stumbled upon a
       | fully functioning and performant Coin Flip Simulator!
        
       | runtimepanic wrote:
       | The interesting part isn't the if-statement count but how quickly
       | the compiler and branch predictor erase the differences. It's a
       | nice demo of why "manual cleverness" rarely beats modern
       | toolchains.
        
       | lubujackson wrote:
       | God help us if that code ever makes it's way onto npm.
       | 
       |  _isEven is a performant, hand-compiled evenness checker for any
       | 32 bit integer. A single file import that does one job and one
       | job only!_
        
         | not-so-darkstar wrote:
         | it follows the UNIX philosophy of doing one thing and donig it
         | well.
        
       | Exuma wrote:
       | This is good stuff
        
       | rossdavidh wrote:
       | Really if you are not making custom silicon for this problem, you
       | are just wasting our time here aren't you.
        
         | robotguy wrote:
         | I mean, this is the ultimate domain for Quantum Computers:
         | 
         | "Is it odd or Even?"
         | 
         | "YES"
        
       | SatvikBeri wrote:
       | > How did I do this? Well I jumped online, using a mix of my
       | early life experience coding emulators and hacking and looked
       | into the x86(-64) architecture manuals to figure out the correct
       | opcodes and format for each instruction. ... Just kidding, that's
       | horrible. I asked ChatGPT
       | 
       | Ok but if you do want to play with writing binary code manually I
       | recommend Casey Muratori's performance course
        
       | fainpul wrote:
       | Any good engineer knows there is no "best" solution, only
       | tradeoffs.
       | 
       | Save space.                 def even_flip_flop(number):
       | even = True         for _ in range(number):           even = not
       | even         return even
       | 
       | Ditto. Sure, this overflows the stack, but you look cool doing
       | it.                 def even_recursive(number):         return
       | True if number == 0 else not even_recursive(number - 1)
       | 
       | Save time. Just buy more RAM.                 table = [True,
       | False] * 1000  # adjust to your needs       def
       | even_lookup(number):         return table[number]
        
         | bobbylarrybobby wrote:
         | You can combine the second and third strategies to hit the
         | sweet spot of time and space.
        
       | taylorallred wrote:
       | Meanwhile:                   not     eax         and     eax, 1
        
       | almosthere wrote:
       | If you were to convert an llm model into code, it would have like
       | 500 billion if statements like that
        
       | zkmon wrote:
       | Infact, some really performant code such as glMatrix.js do not
       | use any for loops for matrix math, just to allow the javascript
       | engine to optimize the code as much as possible.
       | 
       | https://github.com/toji/gl-matrix/blob/master/dist/gl-matrix...
        
       | avandecreme wrote:
       | This reminds me of when I learned to program on my casio
       | calculator.
       | 
       | There was a function to detect a key press which would return a
       | number identifying the pressed key.
       | 
       | I needed to map that number to the letter printed on the key to
       | print it on the screen. I don't remember whether there was no
       | hashmap data structure or I just didn't know about it, but I
       | implemented it with a serie of if.
       | 
       | The problem with that solution is that while mapping A was fast,
       | Z was very slow because it was at the end of the list. That is
       | how I discovered divide and conquer/ dichotomy with if branches.
        
       | dorianmariecom wrote:
       | i tried in ruby up to 1 million (1 billion was taking too long)
       | File.write("check.rb", (["if i == 0\n  puts :even"] +
       | (1..1_000_000).map { |i| "elsif i == #{i}\n  puts :#{i % 2 == 0 ?
       | "even" : "odd"}" } + ["end\n"]).join("\n"))
       | 
       | and added at the top                   i = ARGV.first.to_i
       | 
       | but i'm getting SIGILL                   fish: Job 1, 'ruby
       | check.rb 0' terminated by signal SIGILL (Illegal instruction)
        
         | sedatk wrote:
         | Ooh a new bug.
        
       | ITniggah wrote:
       | "If this illegal and the associated family would have been
       | finally deported..."
        
       | quux wrote:
       | I kept waiting for the payoff to be "The optimizer reduced the
       | entire series of if statements to a single instruction"
        
       | Ensorceled wrote:
       | I just had flash backs to a previous job where I was brought in
       | to optimize another teams builds since they were now taking
       | minutes instead of seconds.
       | 
       | I tracked it down to a folder with thousands of C++ files called
       | things like uint_to_int.cc and inch_to_cm.cc and cm_to_m.cc.
       | Basically the developer in charge of writing the conversion
       | library took our typed units library and autogenerated a C++ file
       | for every possible conversion the application might need to make.
       | 
       | Every time we added a new typed unit it would create another
       | couple of dozen files to be compiled.
        
       | _kst_ wrote:
       | The author missed an opportunity for a much shorter solution for
       | the given problem statement.                   // Check whether a
       | number is odd or even.              #include <stdio.h>
       | #include <stdlib.h>         #include <stdbool.h>
       | static bool is_odd_or_even(unsigned long num) {
       | return true;         }              int main(int argc, char
       | **argv) {             const unsigned long num = strtoul(argv[1],
       | NULL, 10);             printf("%lu is %s odd or even\n",
       | num,                    is_odd_or_even(num) ? "is" : "is not");
       | }
        
         | niccl wrote:
         | Brilliant! Mr Boole would love this
        
       | billforsternz wrote:
       | I know it's silly, but I just want to fix his first version with
       | the minimum possible changes;                 /* Copyright 2023.
       | All unauthorized distribution of this source code          will
       | be persecuted to the fullest extent of the law*/       #include
       | <stdio.h>       #include <stdint.h>       #include <string.h>
       | int main(int argc, char* argv[])       {           uint8_t number
       | = argc>1 ? argv[1][strlen(argv[1])-1]-'0' : printf("Usage: odd-
       | or-even number\n");           if (number == 0)
       | printf("even\n");           if (number == 1)
       | printf("odd\n");           if (number == 2)
       | printf("even\n");           if (number == 3)
       | printf("odd\n");           if (number == 4)
       | printf("even\n");           if (number == 5)
       | printf("odd\n");           if (number == 6)
       | printf("even\n");           if (number == 7)
       | printf("odd\n");           if (number == 8)
       | printf("even\n");           if (number == 9)
       | printf("odd\n");           if (number == 10)
       | printf("even\n");       }
       | 
       | This way it basically works. It's a shame that it doesn't call
       | out a non numeric argument but that's about the only problem. It
       | relies on a trick, printf() returns the number of characters
       | printed, so the error message string needs to be longer than 10.
        
       | asgs wrote:
       | no but thank you. i will stick to using npm's is-odd and is-even
       | packages
        
       | rplnt wrote:
       | Can't you just implement javascript interpreter and import is-
       | even package like normal developers?
        
       ___________________________________________________________________
       (page generated 2025-12-12 23:00 UTC)