Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It seems over-engineered to me. Why go through all the hustle of code generation? It can be solved with a simple “for loop”:

  func isOdd(n int) bool {
    var odd bool
    for i := 0; i < n; i++ {
      odd = !odd
    }
    return odd
  }
Playground link: https://go.dev/play/p/8TIfzGrdWDF

I did not profile this one yet. But my intuition, and my industry experience, tell me that this is fast.



A true production quality implementation should always use recursion.

  func isOdd(n int) bool {
    switch {
    case n == 0:
      return false
    case n > 0:
      return !isOdd(n-1)
    default:
      return !isOdd(n+1)
    }
  }


You can also use beautiful mutual recursion a la ocaml

  let rec isEven n = 
    if n = 0 then true
    else isOdd (n-1)
  and isOdd n = 
    not (isEven n)


FYI ES2015 added tail-call optimization, allowing JS to finally have an elegant isOdd function.


Only Safari supports it, though


This will cause a stack overflow. You can convert that into a loop and make your own stack on the heap if you need very deep recursion.


If you can keep the local variables down, a simple ulimit -s 60000000 should be able to get that stack limit nice and big!

You may need to call setrlimit with an appropriate RLIMIT_STACK, but I think the FFI compatibility should be able to pull that off, right?


> This will cause a stack overflow. You can convert that into a loop and make your own stack on the heap if you need very deep recursion.

Doesn't Go allocate / extend stacks using dynamic allocation rather than having a static limit (e.g. like C)?


In a language with tail-call optimization, it won't.


It will. The negations are only being applied on the way back up the call stack. The mutual recursion version in a sibling post can be made to work though.


Surprisingly, some compilers can automatically turn that to a loop too! Try it on clang and gcc :)


GCC does eliminate one of the recursive calls but retains the other: https://godbolt.org/z/dof4T4vYv

But it also does some magic that I don't quite understand (what do the two `sub` instructions do before the `call`? Do they prepare the stack?) because x86 assembly is so confusing to me sometimes.


this is truely evil :)


I can confirm that the rust version of this one is fast:

    playground::isOdd:
     testq %rdi, %rdi
     setg %al
     andb %dil, %al
     retq
(Click ... beside build to get assembly) https://play.rust-lang.org/?version=stable&mode=release&edit...

Unfortunately the go playground doesn't seem to support emitting assembly?


Shameless plug to claim Rust superiority!1

No, Go playground can not do that :(


https://godbolt.org/ supports emitting assembly for Go while Google's tools catch up!


Good point! Neither gc nor gccgo -O seem to figure this function out :(

https://godbolt.org/z/eMv41nc6Y

Proof, that you must use rust if you want blazingly fast execution of fearlessly pessimized code!


This commands an issue in the Go repo!


Don't forget the companion isEven function:

    func isEven(n int64) bool {
        return !isOdd(n)
    }


Wow you can call a function from a function ? It’ll revolutionize my productivity.


It will iterate infinitely for n=infinite.


Is infinite even or odd?


Yes.


Ideally it should throw exception I guess.


You can improve this with tail recursion.


Does Go default-initialize booleans by any chance? In C, which author had used, this program would be undefined behavior due to reading non-static, uninitialized bool.


Go has “zero” values. The zero value of Boolean is false.

https://go.dev/tour/basics/12


You, sir, are a raging psychopath. You have found a local maxima of brevity and absurdity and I, for one, salute you.


I think this counts as a bottom-up DP solution




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: