Skip to content

Conversation

@Uzlopak
Copy link
Contributor

@Uzlopak Uzlopak commented Aug 14, 2024

Using the recursive way of calculating the gcd is slower than the non-recursive way, especially when using map and reduce.... it basically means calling functions over and over... So this PR aims to reduce the overhad an function calls

benchmark script and results

import { bench, group, run } from 'mitata'
import assert from 'assert'

function euclidianRecursive (a, b) {
  if (b === 0) return a
  return euclidianRecursive(b, a % b)
}

function euclidianLinear (a, b) {
  if (a === 0) return b

  while (b !== 0) {
    const t = b
    b = a % b
    a = t
  }
  return a
}

function euclidianSwap (a, b) {
  if (a === 0) return b
  if (b === 0) return a
  if (a < b) {
    ([a, b] = [b % a, a])
  } else {
    a %= b
  }

  let t = b
  while (b !== 0) {
    t = b
    b = a % b
    a = t
  }
  return a
}

function gcdTest (gcd) {
  let data = [0, 0]
  assert.strictEqual(gcd(...data), 0)

  data = [1, 0]
  assert.strictEqual(gcd(...data), 1)

  data = [0, 1]
  assert.strictEqual(gcd(...data), 1)

  data = [6, 4]
  assert.strictEqual(gcd(...data), 2)

  data = [15, 20]
  assert.strictEqual(gcd(...data), 5)

  data = [20, 15]
  assert.strictEqual(gcd(...data), 5)

  data = [48, 18]
  assert.strictEqual(gcd(...data), 6)
}

function getGreatestCommonDivisor (a, b) {
  if (a === 0) return b
  if (b === 0) return a
  return getGreatestCommonDivisor(b, a % b)
}

gcdTest(getGreatestCommonDivisor)
gcdTest(euclidianRecursive)
gcdTest(euclidianLinear)
gcdTest(euclidianSwap)

group('gcd', () => {
  bench('euclidianRecursive', () => {
    // euclidianRecursive(0, 7890)
    // euclidianRecursive(123456, 0)
    euclidianRecursive(123456, 7890)
    // euclidianRecursive(7890, 45234)
  })
  bench('euclidianLinear', () => {
    // euclidianLinear(0, 7890)
    // euclidianLinear(123456, 0)
    euclidianLinear(123456, 7890)
    // euclidianLinear(7890, 45234)
  })
  bench('euclidianSwap', () => {
    // euclidianSwap(0, 7890)
    // euclidianSwap(123456, 0)
    euclidianSwap(123456, 7890)
    // euclidianSwap(7890, 45234)
  })
})

await run()
aras@aras-Lenovo-Legion-5-17ARH05H:~/workspace/undici$ node benchmarks/lib/gcd.mjs
cpu: AMD Ryzen 7 4800H with Radeon Graphics
runtime: node v23.0.0-nightly20240507be8d64ec14 (x64-linux)

benchmark               time (avg)             (min … max)       p75       p99      p999
---------------------------------------------------------- -----------------------------
• gcd
---------------------------------------------------------- -----------------------------
euclidianRecursive   28.93 ns/iter     (27.93 ns … 140 ns)  28.85 ns  33.45 ns  47.27 ns
euclidianLinear      21.25 ns/iter   (20.26 ns … 59.41 ns)  21.18 ns   25.2 ns  32.26 ns
euclidianSwap        26.71 ns/iter    (20.9 ns … 85.19 ns)  26.56 ns  36.35 ns  39.93 ns

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants