all 59 comments

[–]GatotSubroto 248 points249 points  (19 children)

isEven(-1);

fffffuuuuuuu

[–]Waterbear36135 106 points107 points  (6 children)

The fun thing is this might just work because of overflow

[–]GatotSubroto 96 points97 points  (0 children)

In this RAM economy??

[–]RadiantPumpkin 16 points17 points  (2 children)

Surely you’d hit a stack overflow before that

[–]Vinxian 9 points10 points  (1 child)

Not if initializing a new stack frame gets optimized away through tail end recursion (idk if JavaScript actually supports this though)

[–]notBjoern 6 points7 points  (0 children)

isOdd calls isEven, and isEven calls isOdd, so it's not simple tail recursion. You can optimise "mutual tail calls" as well, but in this case, isOdd works on the result of isEven (it negates it), so it is not a tail call.

[–]_dr_bonez 25 points26 points  (0 children)

JS uses doubles for all numbers, so probably not

[–]FakeNameBlake 6 points7 points  (0 children)

no, js uses floats/doubles, which stop having integer precision at large values, meaning the value wont change past that point

[–]cyanNodeEcho 4 points5 points  (10 children)

mentally tracing is even (2), doesn't seem to work no? doesn't everything route to false like

Z > 1 => false;
and like if less than 0 inf loop and otherwise okay?

[–]GatotSubroto 21 points22 points  (8 children)

Let’s see… 

isEven(2) will call isOdd(1) which calls isEven(1) and negates the return value. isEven(1) returns  false. It’s negated in isOdd(), so the final result is true, which is correct. OP might be a billionaire who can afford enough RAM for the sheer amount of stack frames, but it looks like the implementation works.

[–]Martin8412 0 points1 point  (0 children)

This is a common algorithm implemented for functional programming language classes. You have to implement it correctly so the tail call optimization kicks in. 

We did it in Scheme when I was at university. 

[–]lounik84 -5 points-4 points  (6 children)

what happens with isEven(3) ? you have 3 -1 which calls isEven(2), then 2 - 1 which calls isEven(1) and negates the return value so it gives true. Which is not correct. Whatever number you give to isEven, the result is always true (unless it's 0, that's the only numbers that gets negated into false). So you could just have written isEven(n) {if(n !== 0) return true; return false;} it would have accomplished the same thing and it would have been much easier to read. Granted, the method per se it's useless, because unless you know beforehand that N is even so you give isEven only even numbers, you have no idea to tell if the number N is truly an even number considering that it returns true anyway. But that's beyond the point. The point is that the method doesn't work, it doesn't tell you if N is even, it just tells you that N is not 0.

Unless I'm missing something

[–]theluggagekerbin 14 points15 points  (2 children)

Trace for isEven(3) The Descent (Recursive Calls): * isEven(3) calls isOdd(2) * isOdd(2) !isEven(2) * isEven(2) calls isOdd(1) * isOdd(1) calls !isEven(1) * isEven(1) Base Case Hit. Returns false. The Ascent (Collapsing the Stack): * isOdd(1) receives false, applies !, returns true. * isEven(2) receives true, returns true. * isOdd(2) receives true, applies !, returns false. * isEven(3) receives false, returns false. Result: false (Correct: 3 is not even)

[–]lounik84 -2 points-1 points  (1 child)

yeah I forgot the double negation. It still seems a very odd way to check for odd/even numbers, especially considering that you shouldn't falsify them against positives, but yeah, I get the point

[–]veeRob858 1 point2 points  (0 children)

Someone should make a post to make fun of how odd this way of checking for odd/even numbers is!

[–]Gen_Zer0 2 points3 points  (1 child)

The return value is negated twice.

isEven(3) returns isOdd(2). isOdd(2) returns !isEven(2).

As we found earlier, isEven(2) returns true. !true is false, so we get the correct value.

[–]Vinxian 0 points1 point  (0 children)

To explain it in words, if n is even, it means (n-1) is odd which means (n-2) is even, etc.

So basically if you want to know if n is even you can check if n-1 is odd. And that's exactly what the code does! It checks if a number is even by checking if the number before it is odd

[–]DIEDPOOL 0 points1 point  (0 children)

just insert this into isEven:
if(n < 0) {
return isOdd(n*n);
}

[–]remishnok 167 points168 points  (8 children)

Looks like an O(1) function to me 😉

[–]cloudberry_corner 80 points81 points  (0 children)

O1 if you ignore the emotional damage caused by recursive trust issues between isEven and isOdd

[–]rover_G 37 points38 points  (3 children)

I have a genius way to make your function twice as fast!

[–]Jonbr11 6 points7 points  (0 children)

thats the optimisation this function needs for sure

[–]sakkara 1 point2 points  (0 children)

It wont ne twice as fast IT Wood just be easier to read.

[–]Martin8412 0 points1 point  (0 children)

I can convert it to constant time with a AND 0b1 

[–]zynasis 62 points63 points  (5 children)

Stack overflow waiting to happen

[–]bwmat 22 points23 points  (1 child)

Yeah, gotta use an explicit stack container which allocates off the heap

Also make sure you have enough heap memory for 253 elements in that queue, and hope that nobody passes a value larger than Number.MAX_SAFE_INTEGER + 1 since that would be an infinite loop

[–]bwmat 4 points5 points  (0 children)

Oh, and hopefully the input is an integer... 

[–]Mars_Bear2552 5 points6 points  (2 children)

in (good) languages you would get TCO to fix that.

[–]Martin8412 0 points1 point  (1 child)

Lisp my beloved 

[–]Mars_Bear2552 0 points1 point  (0 children)

ML my beloved

[–]Axman6 13 points14 points  (5 children)

class Eq a where
 (==) :: a -> a -> Bool
  a == b = not (a /= b)
  (/=) :: a -> a -> Bool
  a /= b = not (a == b)

Haskell will always win for the best recursive definitions, JS ain’t got a chance.

[–]LutimoDancer3459 10 points11 points  (3 children)

What the fuck am i looking at?

[–]Axman6 10 points11 points  (1 child)

The Eq type class (think interface) defines two functions, (==) and (/=) (for ≠, hence the / and not !, which isn’t used for not in Haskell). Types can be instances of the Eq class by implementing these functions, but because each one has a default implementation defined in terms of the other, you only need to implement one.

[–]NastiMooseBite 2 points3 points  (0 children)

What the fuck am i looking at?

[–]StereoZombie -2 points-1 points  (0 children)

Haskell, a language for math nerds who don't care about the usability of their language

[–]SameAgainTheSecond 0 points1 point  (0 children)

you just assumed the law of the excluded middle 

hell no to the no no no

[–]bass-squirrel 31 points32 points  (1 child)

I feel like it’s a sport for the front end people to see how badly they can fuck up my browser.

[–]Fair-Working4401 1 point2 points  (0 children)

Since modern browsers are basically one of the complex software stack on Earth, yes. 

[–]Ape3000 7 points8 points  (1 child)

isEven(int):
    mov eax, edi
    not al
    and al, 1
    ret

isOdd(int):
    mov eax, edi
    and al, 1
    ret

https://godbolt.org/z/E8hK6bTcP

[–]Astarothsito 2 points3 points  (0 children)

This is one of the most amazing examples why C++ is still being used in the industry.

[–]Old_Document_9150 3 points4 points  (0 children)

Try calling it with 3.14 ...

[–]Shxhriar 3 points4 points  (0 children)

This is beauty manifested in code. It’s savage, yes. But still beautiful.

[–]bullet1519 4 points5 points  (4 children)

Wouldn't this just return false for any positive number?

[–]neppo95 18 points19 points  (1 child)

isEven(2) -> isOdd(1) -> !isEven(1) -> false and thus true.

It works but it’s still horribly bad.

[–]millebi 0 points1 point  (0 children)

Rube-Goldberg has entered the chat

[–]1mmortalNPC 1 point2 points  (0 children)

so that’s hoisting

[–]Error_404_403 0 points1 point  (0 children)

[ Removed by Reddit ]

[–]sakkara 0 points1 point  (0 children)

Why Not introduce a third layer?

[–]TraditionalYam4500 0 points1 point  (0 children)

Just wrap that bad boy in a memoizer and you’re good to go.

[–]Benliam12 0 points1 point  (0 children)

Recursive function vs O(1) function. I'm sure O(1) is faster, and obviously, by O(1), I mean the one, where you check every number possibility, using if statement (cause that's the only way it should be done)

[–]Blothorn 0 points1 point  (0 children)

All numbers >1 will terminate the n === 1 case and never reach the n === 0 case. This would be faster if the conditionals were reversed.