Skip to content

Commit

Permalink
Implement ceiling power of two
Browse files Browse the repository at this point in the history
  • Loading branch information
frostburn committed Jan 13, 2024
1 parent e08c4aa commit c26cc03
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {describe, it, expect} from 'vitest';
import {
arraysEqual,
binomial,
ceilPow2,
circleDifference,
circleDistance,
clamp,
Expand Down Expand Up @@ -152,3 +153,29 @@ describe('Pitch distance with circle equivalence', () => {
expect(diff).toBeCloseTo(247.741);
});
});

describe('Ceiling power of two', () => {
it('works with small values', () => {
const x = 1 + Math.random() * (2 ** 30 - 2);
const p2 = ceilPow2(x);
expect(x).toBeLessThanOrEqual(p2);
expect(p2).toBeLessThan(2 * x);
expect(Math.log2(p2)).toBeCloseTo(Math.round(Math.log2(p2)));
});

it('works with tiny values', () => {
const x = Math.random();
const p2 = ceilPow2(x);
expect(x).toBeLessThanOrEqual(p2);
expect(p2).toBeLessThan(2 * x);
expect(Math.log2(p2)).toBeCloseTo(Math.round(Math.log2(p2)));
});

it('works with large values', () => {
const x = 2 ** 31 + Math.random() * 2 ** 37;
const p2 = ceilPow2(x);
expect(x).toBeLessThanOrEqual(p2);
expect(p2).toBeLessThan(2 * x);
expect(Math.log2(p2)).toBeCloseTo(Math.round(Math.log2(p2)));
});
});
15 changes: 15 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,18 @@ export function circleDifference(a: number, b: number, equaveCents = 1200.0) {
export function circleDistance(a: number, b: number, equaveCents = 1200.0) {
return Math.abs(circleDifference(a, b, equaveCents));
}

/**
* Calculate the smallest power of two greater or equal to the input value.
* @param x Value to compare to.
* @returns Smallest `2**n` such that `x <= 2**n`.
*/
export function ceilPow2(x: number) {
if (x >= 1 && x < 0x40000000) {
return 1 << (32 - Math.clz32(x - 1));
}
if (x <= 0) {
return 0;
}
return 2 ** Math.ceil(Math.log2(x));
}

0 comments on commit c26cc03

Please sign in to comment.