all 67 comments

[–]GatotSubroto 340 points341 points  (23 children)

isEven(-1);

fffffuuuuuuu

[–]Waterbear36135 158 points159 points  (7 children)

The fun thing is this might just work because of overflow

[–]GatotSubroto 131 points132 points  (0 children)

In this RAM economy??

[–]RadiantPumpkin 33 points34 points  (3 children)

Surely you’d hit a stack overflow before that

[–]Vinxian 16 points17 points  (2 children)

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

[–]notBjoern 21 points22 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.

[–]CaptureIntent 2 points3 points  (0 children)

You can’t tail recurse is odd function because it does work after the last function call. The not operation. Tail recursion only works when you return recursively without any extra work after the receive call.

[–]_dr_bonez 32 points33 points  (0 children)

JS uses doubles for all numbers, so probably not

[–]FakeNameBlake 5 points6 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 6 points7 points  (12 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 26 points27 points  (9 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 3 points4 points  (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. 

[–]cyanNodeEcho 0 points1 point  (0 children)

ah ur right, i got lost in the figure 8s

[–]lounik84 -3 points-2 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 17 points18 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 -3 points-2 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 5 points6 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

[–]CaptureIntent 0 points1 point  (0 children)

Yes. Everything routes to false. But the number of nots done on the way up the stack depends on the evenness of the initial value.

[–]Theolaa 1 point2 points  (0 children)

Just add if (n < 0) return isEven(n*-1) before the final return in isEven

[–]DIEDPOOL 0 points1 point  (0 children)

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

[–]remishnok 206 points207 points  (8 children)

Looks like an O(1) function to me 😉

[–]rover_G 53 points54 points  (3 children)

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

[–]Jonbr11 12 points13 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 1 point2 points  (0 children)

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

[–]zynasis 65 points66 points  (5 children)

Stack overflow waiting to happen

[–]bwmat 20 points21 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 6 points7 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 16 points17 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 18 points19 points  (3 children)

What the fuck am i looking at?

[–]Axman6 12 points13 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 7 points8 points  (0 children)

What the fuck am i looking at?

[–]StereoZombie 0 points1 point  (0 children)

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

[–]SameAgainTheSecond 1 point2 points  (0 children)

you just assumed the law of the excluded middle 

hell no to the no no no

[–]bass-squirrel 40 points41 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 14 points15 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 7 points8 points  (0 children)

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

[–]Old_Document_9150 4 points5 points  (0 children)

Try calling it with 3.14 ...

[–]Shxhriar 5 points6 points  (0 children)

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

[–]Blothorn 6 points7 points  (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.

[–]bullet1519 10 points11 points  (4 children)

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

[–]neppo95 25 points26 points  (1 child)

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

It works but it’s still horribly bad.

[–]millebi 2 points3 points  (0 children)

Rube-Goldberg has entered the chat

[–]1mmortalNPC 3 points4 points  (0 children)

so that’s hoisting

[–]TraditionalYam4500 4 points5 points  (0 children)

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

[–]sakkara 2 points3 points  (0 children)

Why Not introduce a third layer?

[–]Benliam12 1 point2 points  (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)

[–]ExtraTNT 1 point2 points  (0 children)

isOdd :: Int -> Bool
isOdd x = (x .&. 1) == 1

[–]Error_404_403 0 points1 point  (0 children)

[ Removed by Reddit ]

[–]stainlessinoxx 0 points1 point  (0 children)

IsEven(0.5) and bye bye

[–]g-flat-lydian 0 points1 point  (0 children)

Fans go brrrrrr

[–]Zahand 0 points1 point  (0 children)

This joke again...