Skip to content

Commit

Permalink
feat(docs): add jsdoc and readme notes
Browse files Browse the repository at this point in the history
  • Loading branch information
rektdeckard committed Oct 18, 2023
1 parent 29f16e4 commit 7ea56cb
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 68 deletions.
167 changes: 165 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ A collection of interesting helpers, data structures, and utility types for mess
- [Numerics](#numerics)
- [Constants](#constants)
- [ComplexNumber](#complexnumber)
- [RationalNumber](#rationalnumber)
- [Wrapping](#wrapping)
- [Saturating](#saturating)
- [Types](#utility-types)
Expand All @@ -30,13 +31,19 @@ A collection of interesting helpers, data structures, and utility types for mess
- [Transforms](#transforms)
- [clamp](#clamp)
- [lerp](#lerp)
- [gcf](#gcf)
- [lcm](#lcm)
- [trailingZeros](#trailingzeros)
- [Utilities](#utilities)
- [Range](#range)
- [Random](#random)
- [Comparator](#comparator)
- [objectHash](#objecthash)
- [Assertions](#assertions)
- [castInteger](#castinteger)
- [assertInteger](#assertinteger)
- [assertNatural](#assertnatural)
- [assertCounting](#assertcounting)
- [assertValidRange](#assertvalidrange)

## Installation
Expand Down Expand Up @@ -130,6 +137,89 @@ const c = ComplexNumber.from(b); // 7 - i
b.eq(c); // true
```

### RationalNumber

A rational number class for fraction arithmetic without loss of precision. Operations are only guaranteed where numerator and denominator are within `Number.MIN_SAFE_INTEGER` and `Number.MAX_SAFE_INTEGER`.

<details>
<summary>Class Signature</summary>
<p>

```ts
class RationalNumber implements Number {
constructor(numerator: number, denominator: number = 1);

get numerator(): number;
get denominator(): number;

static from(...input: RationalLike | [fraction: string]): RationalNumber;
static parse(fraction: string): RationalNumber;

recip(): RationalNumber;
add(...addend: RationalLike): RationalNumber;
sub(...subtrahend: RationalLike): RationalNumber;
mul(...multiplicand: RationalLike): RationalNumber;
div(...divisor: RationalLike): RationalNumber;
pow(exponent: number): RationalNumber;
mod(modulus: number): RationalNumber;
abs(): RationalNumber;
eq(...other: RationalLike): boolean;
gt(...other: RationalLike): boolean;
gte(...other: RationalLike): boolean;
lt(...other: RationalLike): boolean;
lte(...other: RationalLike): boolean;

toFraction(options?: RationalFormatOptions): string;

valueOf(): number;
toFixed(fractionDigits?: number | undefined): string;
toExponential(fractionDigits?: number | undefined): string;
toPrecision(precision?: number | undefined): string;
toString(radix?: number | undefined): string;
}

type RationalFormat = "space" | "nospace" | "unicode";

type RationalFormatOptions = {
mixed?: boolean;
format?: RationalFormat;
};

type RationalLike =
| [rational: RationalNumber]
| [numerator: number]
| [numerator: number, denominator: number];
```

</p>
</details>

```ts
import { RationalNumber } from "kdim";

const a = new RationalNumber(5, 31); // construct from numerator, denominator
const b = RationalNumber.parse("3 / 9"); // parse from string (spaces are not required)

const result = a
.add(b) // rationals as arguments
.mul(12) // integer arguments
.div(5, 4) // implicit rational arguments
.toFraction(); // "116/155"

RationalNumber.parse("16 / 24").eq("2 / 3"); // true
```

RationalNumbers are immutable, so arithmetic methods always produce new values. They will always simplify to their most reduced form upon construction.

Serializing a RationalNumber by calling the `toFraction` allows to specify whether it should be in `mixed` number or irrational format (the default), as well as whether the unicode `FRACTION SLASH` (`\u2044`) character should be used instead of a typical forward slash (`/`), which produces small fractions on some platforms, E.G. `3⁄4`.

```ts
import { RationalNumber } from "kdim";

RationalNumber.from("3/4").toFraction({ format: "nospace" }); // "3/4"
RationalNumber.from("3/4").toFraction({ format: "unicode" }); // "3⁄4"
```

### Wrapping

A wrapping integer class, allowing a value to be constrained to an arbitrary range, and wrapping around the range when arithmetic operations cause it to overflow or underflow.
Expand Down Expand Up @@ -379,15 +469,18 @@ class Matrix<M extends number, N extends number>
get data(): MatrixLike<M, N>;

isSquare(): boolean;
isOrthogonal(): boolean;

at(i: number, j: number): number | undefined;
row(i: number): Tuple<number, N> | undefined;
col(j: number): Tuple<number, M> | undefined;
clone(): Matrix<M, N>;
submatrix<M extends number, N extends number>(
removeRows: number[],
removeCols: number[]
options: SubmatrixOptions
): Matrix<number, number>;
augment<O extends number, P extends number>(
other: MatrixOperand<M, O>
): Matrix<M, P>;

trace(): number;
determinant(): number | undefined;
Expand All @@ -401,6 +494,7 @@ class Matrix<M extends number, N extends number>
): MatrixResult<M, N, I>;
pow(k: number): Matrix<M, M>;
eq(other: MatrixOperand<M, N>, tolerance?: number): boolean;
dot(other: MatrixOperand<M, 1>): number;

[Symbol.iterator](): Iterator<Vec<N>>;
}
Expand Down Expand Up @@ -715,6 +809,75 @@ const interpolated = lerp(1, 99, value); // 40.2

> Note: throws a RangeError when the value is outside of `[0, 1]`
### gcf

Find the Greatest Common Factor of two integers.

<details>
<summary>Function Signature</summary>
<p>

```ts
function gcf(a: number, b: number): number;
```

</p>
</details>

```ts
import { gcf } from "kdim";

gcf(45, 420); // 15
```

> Note: throws a RangeError when `a` or `b` are non-integral.
### lcm

Find the Least Common Multiple of two integers.

<details>
<summary>Function Signature</summary>
<p>

```ts
function lcm(a: number, b: number): number;
```

</p>
</details>

```ts
import { lcm } from "kdim";

lcm(6, 20); // 60
```

> Note: throws a RangeError when `a` or `b` are non-integral.
### trailingZeros

Compute the number of trailing zeros in a number's 32-bit representation, equivalent to its largest power-of-two divisor.

<details>
<summary>Function Signature</summary>
<p>

```ts
function trailingZeros(n: number): number;
```

</p>
</details>

```ts
import { trailingZeros } from "kdim";

trailingZeros(24); // 3
```

> Note: throws a RangeError when `n` is non-integral.
## Utilities

### Range
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kdim",
"version": "0.3.7",
"version": "0.4.0",
"description": "Utility data stuctures, math, and types for JS",
"author": {
"name": "Tobias Fried",
Expand Down
59 changes: 14 additions & 45 deletions src/math/matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ export type MatrixOperand<M extends number, N extends number> =
| MatrixLike<M, N>
| number[][];

export type SubmatrixOptions =
| {
removeRows: number[];
removeCols: number[];
xywh?: never;
}
| {
xywh: [number, number] | [number, number, number, number];
removeRows?: never;
removeCols?: never;
};

type MatrixResult<
M extends number,
N extends number,
Expand All @@ -27,7 +39,7 @@ export type MTXOptions = {
* A concrete Matrix class for simple linear algebra, currently only supporting
* simple numbers, but with plans to add support for complex numbers.
*
* Implements {@link Iterable} over {@link Vec}
* Implements {@link Iterable} over {@link Tuple}
*/
export class Matrix<M extends number, N extends number>
implements Iterable<Tuple<number, N>>
Expand Down Expand Up @@ -278,17 +290,7 @@ export class Matrix<M extends number, N extends number>
removeRows,
removeCols,
xywh,
}:
| {
removeRows: number[];
removeCols: number[];
xywh?: never;
}
| {
xywh: [number, number] | [number, number, number, number];
removeRows?: never;
removeCols?: never;
}) {
}: SubmatrixOptions) {
if (!!xywh) {
const [x, y, w, h] = xywh;
const data = this.#data
Expand Down Expand Up @@ -458,39 +460,6 @@ export class Matrix<M extends number, N extends number>
} else {
return;
}

// {
// // DEPRECATED: old method
// const am = this.clone();
// const im = Matrix.identity<M>(am.rows as M);

// for (let fd = 0; fd < am.rows; fd++) {
// let fdScaler = 1.0 / am.at(fd, fd)!;

// for (let j = 0; j < am.cols; j++) {
// (am.#data[fd][j] as number) *= fdScaler;
// (im.#data[fd][j] as number) *= fdScaler;
// }

// for (let i = 0; i < am.rows; i++) {
// if (i === fd) continue;

// const rowScaler = am.at(i, fd)!;
// for (let j = 0; j < am.cols; j++) {
// (am.#data[i][j] as number) =
// am.at(i, j)! - rowScaler * am.at(fd, j)!;
// (im.#data[i][j] as number) =
// im.at(i, j)! - rowScaler * im.at(fd, j)!;
// }
// }
// }

// if (!(this as any).mul(im).eq(Matrix.identity(this.rows), tolerance)) {
// throw new Error(`Matrix inversion failed!`);
// }

// return im;
// }
}

transpose(): Matrix<N, M> {
Expand Down
56 changes: 36 additions & 20 deletions src/math/rational.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export type RationalLike =
| [numerator: number]
| [numerator: number, denominator: number];

/**
* A rational number class for fraction arithmetic without loss of precision.
* Operations are only guaranteed where numerator and denominator are within
* {@link Number.MIN_SAFE_INTEGER} and {@link Number.MAX_SAFE_INTEGER}.
*/
export class RationalNumber
implements
Number,
Expand Down Expand Up @@ -230,26 +235,6 @@ export class RationalNumber
return numerator <= otherNumerator;
}

valueOf() {
return this.numerator / this.denominator;
}

toFixed(fractionDigits?: number | undefined): string {
return this.valueOf().toFixed(fractionDigits);
}

toExponential(fractionDigits?: number | undefined): string {
return this.valueOf().toExponential(fractionDigits);
}

toPrecision(precision?: number | undefined): string {
return this.valueOf().toPrecision(precision);
}

toString(_radix?: number | undefined): string {
return this.toFraction();
}

toFraction({
mixed = false,
format = "nospace",
Expand Down Expand Up @@ -279,4 +264,35 @@ export class RationalNumber

return `${this.numerator}${separator}${this.denominator}`;
}

valueOf() {
return this.numerator / this.denominator;
}

toFixed(fractionDigits?: number | undefined): string {
return this.valueOf().toFixed(fractionDigits);
}

toExponential(fractionDigits?: number | undefined): string {
return this.valueOf().toExponential(fractionDigits);
}

toPrecision(precision?: number | undefined): string {
return this.valueOf().toPrecision(precision);
}

toString(radix?: number | undefined): string {
return this.valueOf().toString(radix);
}

get [Symbol.toStringTag]() {
return "RationalNumber";
}

[Symbol.toPrimitive](hint: string) {
if (hint === "number") {
return this.valueOf();
}
return this.toFraction({ mixed: false, format: "nospace" });
}
}
Loading

0 comments on commit 7ea56cb

Please sign in to comment.