1
0
mirror of https://github.com/robonen/tools.git synced 2026-03-20 02:44:45 +00:00

refactor(packages/stdlib): separate math utils штещ basic and bigint versions

This commit is contained in:
2024-09-30 06:19:16 +07:00
parent db7e35d152
commit 061d45f6fd
8 changed files with 154 additions and 69 deletions

View File

@@ -0,0 +1,13 @@
/**
* Clamps a number between a minimum and maximum value
*
* @param {number} value The number to clamp
* @param {number} min Minimum value
* @param {number} max Maximum value
* @returns {number} The clamped number
*
* @since 0.0.1
*/
export function clamp(value: number, min: number, max: number) {
return Math.min(Math.max(value, min), max);
}

View File

@@ -0,0 +1,61 @@
import {describe, it, expect} from 'vitest';
import {inverseLerp, lerp} from './index';
describe('lerp', () => {
it('interpolates between two values', () => {
const result = lerp(0, 10, 0.5);
expect(result).toBe(5);
});
it('returns start value when t is 0', () => {
const result = lerp(0, 10, 0);
expect(result).toBe(0);
});
it('returns end value when t is 1', () => {
const result = lerp(0, 10, 1);
expect(result).toBe(10);
});
it('handles negative interpolation values', () => {
const result = lerp(0, 10, -0.5);
expect(result).toBe(-5);
});
it('handles interpolation values greater than 1', () => {
const result = lerp(0, 10, 1.5);
expect(result).toBe(15);
});
});
describe('inverseLerp', () => {
it('returns 0 when value is start', () => {
const result = inverseLerp(0, 10, 0);
expect(result).toBe(0);
});
it('returns 1 when value is end', () => {
const result = inverseLerp(0, 10, 10);
expect(result).toBe(1);
});
it('interpolates correctly between two values', () => {
const result = inverseLerp(0, 10, 5);
expect(result).toBe(0.5);
});
it('handles values less than start', () => {
const result = inverseLerp(0, 10, -5);
expect(result).toBe(-0.5);
});
it('handles values greater than end', () => {
const result = inverseLerp(0, 10, 15);
expect(result).toBe(1.5);
});
it('handles same start and end values', () => {
const result = inverseLerp(10, 10, 10);
expect(result).toBe(0);
});
});

View File

@@ -0,0 +1,27 @@
/**
* Linearly interpolates between two values
*
* @param {number} start The start value
* @param {number} end The end value
* @param {number} t The interpolation value
* @returns {number} The interpolated value
*
* @since 0.0.2
*/
export function lerp(start: number, end: number, t: number) {
return start + t * (end - start);
}
/**
* Inverse linear interpolation between two values
*
* @param {number} start The start value
* @param {number} end The end value
* @param {number} value The value to interpolate
* @returns {number} The interpolated value
*
* @since 0.0.2
*/
export function inverseLerp(start: number, end: number, value: number) {
return start === end ? 0 : (value - start) / (end - start);
}

View File

@@ -0,0 +1,46 @@
import {describe, expect, it} from 'vitest';
import {remap} from './index';
describe('remap', () => {
it('map values from one range to another', () => {
// value at midpoint
expect(remap(5, 0, 10, 0, 100)).toBe(50);
// value at min
expect(remap(0, 0, 10, 0, 100)).toBe(0);
// value at max
expect(remap(10, 0, 10, 0, 100)).toBe(100);
// value outside range (below)
expect(remap(-5, 0, 10, 0, 100)).toBe(0);
// value outside range (above)
expect(remap(15, 0, 10, 0, 100)).toBe(100);
// value at midpoint of negative range
expect(remap(75, 50, 100, -50, 50)).toBe(0);
// value at midpoint of negative range
expect(remap(-25, -50, 0, 0, 100)).toBe(50);
});
it('handle floating-point numbers correctly', () => {
// floating-point value
expect(remap(3.5, 0, 10, 0, 100)).toBe(35);
// positive floating-point ranges
expect(remap(1.25, 0, 2.5, 0, 100)).toBe(50);
// negative floating-point value
expect(remap(-2.5, -5, 0, 0, 100)).toBe(50);
// negative floating-point ranges
expect(remap(-1.25, -2.5, 0, 0, 100)).toBe(50);
});
it('handle edge cases', () => {
// input range is zero (should return output min)
expect(remap(5, 0, 0, 0, 100)).toBe(0);
});
});

View File

@@ -1,4 +1,5 @@
import { clamp } from "../clamp"; import { clamp } from '../clamp';
import {inverseLerp, lerp} from '../lerp';
/** /**
* Map a value from one range to another * Map a value from one range to another
@@ -9,15 +10,14 @@ import { clamp } from "../clamp";
* @param {number} out_min The minimum value of the output range * @param {number} out_min The minimum value of the output range
* @param {number} out_max The maximum value of the output range * @param {number} out_max The maximum value of the output range
* @returns {number} The mapped value * @returns {number} The mapped value
*
* @since 0.0.1
*/ */
export function mapRange(value: number, in_min: number, in_max: number, out_min: number, out_max: number): number { export function remap(value: number, in_min: number, in_max: number, out_min: number, out_max: number) {
// Zero input range means invalid input, so return lowest output range value
if (in_min === in_max) if (in_min === in_max)
return out_min; return out_min;
// To ensure the value is within the input range, clamp it
const clampedValue = clamp(value, in_min, in_max); const clampedValue = clamp(value, in_min, in_max);
// Finally, map the value from the input range to the output range return lerp(out_min, out_max, inverseLerp(in_min, in_max, clampedValue));
return (clampedValue - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
} }

View File

@@ -1,16 +0,0 @@
/**
* Clamps a number between a minimum and maximum value
*
* @param {number} value The number to clamp
* @param {number} min Minimum value
* @param {number} max Maximum value
* @returns {number} The clamped number
*/
export function clamp(value: number, min: number, max: number): number {
// The clamp function takes a value, a minimum, and a maximum as parameters.
// It ensures that the value falls within the range defined by the minimum and maximum values.
// If the value is less than the minimum, it returns the minimum value.
// If the value is greater than the maximum, it returns the maximum value.
// Otherwise, it returns the original value.
return Math.min(Math.max(value, min), max);
}

View File

@@ -1,46 +0,0 @@
import { describe, expect, it } from 'vitest';
import { mapRange } from './index';
describe('mapRange', () => {
it('map values from one range to another', () => {
// value at midpoint
expect(mapRange(5, 0, 10, 0, 100)).toBe(50);
// value at min
expect(mapRange(0, 0, 10, 0, 100)).toBe(0);
// value at max
expect(mapRange(10, 0, 10, 0, 100)).toBe(100);
// value outside range (below)
expect(mapRange(-5, 0, 10, 0, 100)).toBe(0);
// value outside range (above)
expect(mapRange(15, 0, 10, 0, 100)).toBe(100);
// value at midpoint of negative range
expect(mapRange(75, 50, 100, -50, 50)).toBe(0);
// value at midpoint of negative range
expect(mapRange(-25, -50, 0, 0, 100)).toBe(50);
});
it('handle floating-point numbers correctly', () => {
// floating-point value
expect(mapRange(3.5, 0, 10, 0, 100)).toBe(35);
// positive floating-point ranges
expect(mapRange(1.25, 0, 2.5, 0, 100)).toBe(50);
// negative floating-point value
expect(mapRange(-2.5, -5, 0, 0, 100)).toBe(50);
// negative floating-point ranges
expect(mapRange(-1.25, -2.5, 0, 0, 100)).toBe(50);
});
it('handle edge cases', () => {
// input range is zero (should return output min)
expect(mapRange(5, 0, 0, 0, 100)).toBe(0);
});
});