Skip to content

wrap function ​

Wraps a number into [min, max[ with an always-positive modulo, like a heading wrapping at 360°.

ts
import { wrap } from 'utils';

Signature ​

ts
export function wrap(value: number, min: number, max: number): number

Parameters ​

NameDescription
valueThe number to wrap.
minThe included bound.
maxThe excluded bound.

Returns ​

The equivalent value in [min, max[.

Example ​

ts
wrap(370, 0, 360); // 10
wrap(-10, 0, 360); // 350

Tests ​

Line coverage: 100 %.

  • ✅ wraps 370 into [0, 360[ as 10
  • ✅ wraps -10 into [0, 360[ as 350
  • ✅ wraps 360 into [0, 360[ as 0
  • ✅ wraps -360 into [0, 360[ as 0
  • ✅ wraps -720.5 into [0, 360[ as 359.5
  • ✅ wraps 5 into [10, 20[ as 15
  • ✅ wraps 25 into [20, 10[ as 15
  • ✅ never returns -0

Source ​

src/math/wrap.ts (on GitHub)

Source code
ts
/**
 * Wraps a number into [min, max[ with an always-positive modulo, like a heading wrapping at 360°.
 *
 * @param value - The number to wrap.
 * @param min - The included bound.
 * @param max - The excluded bound.
 * @returns The equivalent value in [min, max[.
 * @example
 * wrap(370, 0, 360); // 10
 * wrap(-10, 0, 360); // 350
 */
export function wrap(value: number, min: number, max: number): number {
  const span = max - min;
  return ((((value - min) % span) + span) % span) + min;
}
Test file
ts
import { wrap } from './wrap';

describe(wrap, () => {
  it.for([
    [370, 0, 360, 10],
    [-10, 0, 360, 350],
    [360, 0, 360, 0],
    [-360, 0, 360, 0],
    [-720.5, 0, 360, 359.5],
    [5, 10, 20, 15],
    [25, 20, 10, 15],
  ] as const)('wraps %s into [%s, %s[ as %s', ([value, min, max, expected]) => {
    expect(wrap(value, min, max)).toBe(expected);
  });

  it('never returns -0', () => {
    expect(Object.is(wrap(-360, 0, 360), 0)).toBe(true);
  });
});

Keywords: wrap, math, function

Generated from the JSDoc of the sources.