Skip to content

Commit

Permalink
Log and trig functions
Browse files Browse the repository at this point in the history
todo: Unit testing
  • Loading branch information
Jsoto22 committed Apr 21, 2024
1 parent 5830249 commit 53de852
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 73 deletions.
93 changes: 84 additions & 9 deletions src/big-decimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import { compareTo, lessThan } from "./compareTo";
import { subtract, negate } from "./subtract";
import { RoundingModes as Modes, RoundingModes } from "./roundingModes";
import { stripTrailingZero } from "./stripTrailingZero";
import { cbRoot, exp, pow, sqRoot } from "./pow";
import { Euler, factorial } from "./utils";
import { cbRoot, pow, sqRoot } from "./pow";
import { factorial } from "./utils";
import { cos, sin, tan } from "./trig";
import { ln, log, ln2, log10, exp, LN2, LN10, LN2E, LN10E, Euler, expm1 } from "./logarithm";

class bigDecimal {
private value: string;
Expand Down Expand Up @@ -226,6 +228,8 @@ class bigDecimal {
return new bigDecimal(negate(this.value));
}

// Powers

static pow(base: number|string, exponent: string) {
base = bigDecimal.validate(base);
exponent = bigDecimal.validate(exponent);
Expand All @@ -237,6 +241,16 @@ class bigDecimal {
return new bigDecimal(pow(this.value, exponent, 32));
}

// Roots

static get SQRT1_2() {
return sqRoot('.5');
}

static get SQRT2() {
return sqRoot('2');
}

static sqRoot(number: number|string): string {
number = bigDecimal.validate(number);
return sqRoot(number);
Expand All @@ -255,18 +269,79 @@ class bigDecimal {
return new bigDecimal(cbRoot(this.value));
}

static exp(base: number|string): string {
base = bigDecimal.validate(base);
return exp(base);
}
// Logarithms

static get E() {
return Euler(32);
}

static factorial(base: number|string): string {
base = bigDecimal.validate(base);
return factorial(base);
static get LN2(){
return LN2
}

static get LN10(){
return LN10
}

static get LN2E(){
return LN2E
}

static get LN10E(){
return LN10E
}

static log2(number: number|string){
number = bigDecimal.validate(number);
return ln2(number)
}

static log10(number: number|string){
number = bigDecimal.validate(number);
return log10(number)
}

static log1p(number: number|string){
number = bigDecimal.validate(number);
return log(add('1', number))
}

static log(number: number|string){
number = bigDecimal.validate(number);
return log(number)
}

static exp(number: number|string): string {
number = bigDecimal.validate(number);
return exp(number);
}

static expm1(number: number|string): string {
number = bigDecimal.validate(number);
return expm1(number)
}

// Trig
static sin(number: number|string): string {
number = bigDecimal.validate(number);
return sin(number);
}

static cos(number: number|string): string {
number = bigDecimal.validate(number);
return cos(number);
}

static tan(number: number|string): string {
number = bigDecimal.validate(number);
return tan(number);
}

// Misc.

static factorial(number: number|string): string {
number = bigDecimal.validate(number);
return factorial(number);
}

static stripTrailingZero(number) {
Expand Down
Empty file added src/logarithm.spec.ts
Empty file.
76 changes: 76 additions & 0 deletions src/logarithm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { add } from "./add";
import { lessThan, equals, greaterThan } from "./compareTo";
import { divide } from "./divide";
import { multiply } from "./multiply";
import { pow } from "./pow";
import { roundOff } from "./round";
import { subtract } from "./subtract";
import { factorial, sigma, tolerance } from "./utils";

export const LN2 = ln('2');
export const LN2E = ln2(Euler(32));
export const LN10 = ln('10');
export const LN10E = log10(Euler(32));

export function Euler(precision: number = 32) {
precision = Math.max(16, precision)
return roundOff(sigma(0, precision, (n: string | number)=>{
return divide('1', factorial(n), precision + 1)
}), precision);
}

export function exp(exponent: number | string) {
return pow(Euler(32), exponent)
}

export function expm1(exponent: number | string) {
return subtract('1', pow(Euler(32), exponent))
}

export function ln(x: string | number = 2) {
x = x.toString();
if (lessThan(x, '0', true)) {
throw "Error: x must be greater than 0";
}

if (equals(x, '1')) {
return '0'; // ln(1) = 0
}

let result = '0';
let term = divide(subtract(x, '1'), add(x, '1'), 33);
let i = 0;
while (true) {
i++
let iteration = subtract(multiply('2', i), '1');
let next = multiply(divide('1', iteration, 33), pow(term, iteration))
if (lessThan(next, tolerance(32)) || i == 100) {
return roundOff(multiply('2', add(result, next)), 32)
}
result = add(result, next);
}

// return multiply('2', result)
}

export function ln2(x: string | number = 2) {
x = x.toString();
if (lessThan(x, '0', true)) {
throw "Error: x must be greater than 0";
}
let result = '0';
while (greaterThan(x, '2', true)) {
x = divide(x, 2, 33);
result = add(result, '1');
}
var fractionalPart = ln(x);
return roundOff(add(result, divide(fractionalPart, LN2,33)), 32);
}

export function log(base: string | number) {
return roundOff(multiply(ln2(base), LN10), 32)
}

export function log10(base: string | number) {
return divide(log(base), LN10, 32)
}
8 changes: 4 additions & 4 deletions src/modulus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { negate, subtract } from './subtract';
import { RoundingModes } from './roundingModes';
import { abs } from './abs';

export function modulusE(n: number | string, base: number | string = 1, percision: number | undefined = undefined) {
export function modulusE(n: number | string, base: number | string = 1, precision: number | undefined = undefined) {

if (base == 0) {
throw new Error('Cannot divide by 0');
Expand All @@ -16,10 +16,10 @@ export function modulusE(n: number | string, base: number | string = 1, percisio

validate(base);

return subtract(n, multiply(base, roundOff(divide(n, base, percision), 0, RoundingModes.FLOOR)));
return subtract(n, multiply(base, roundOff(divide(n, base, precision), 0, RoundingModes.FLOOR)));
}

export function modulus(dividend: number | string, divisor: number | string = 1, percision: number | undefined = undefined) {
export function modulus(dividend: number | string, divisor: number | string = 1, precision: number | undefined = undefined) {
if (divisor == 0) {
throw new Error('Cannot divide by 0');
}
Expand All @@ -29,7 +29,7 @@ export function modulus(dividend: number | string, divisor: number | string = 1,

validate(divisor);

const result = modulusE(abs(dividend), abs(divisor), percision);
const result = modulusE(abs(dividend), abs(divisor), precision);
return (dividend.includes('-')) ? negate(result) : result;
}

Expand Down
73 changes: 35 additions & 38 deletions src/pow.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { abs } from "./abs";
import { compareTo, greaterThan, isExatclyOne, isExatclyZero, lessThan } from "./compareTo";
import { compareTo, equals, greaterThan, isExatclyOne, isExatclyZero, lessThan } from "./compareTo";
import { divide } from "./divide";
import { modulus } from "./modulus";
import { multiply } from "./multiply";
Expand All @@ -8,8 +8,7 @@ import { RoundingModes } from "./roundingModes";
import { stripTrailingZero } from "./stripTrailingZero";
import { negate as negateFn, subtract } from "./subtract";
import { add } from "./add";
import { Euler, tolerance } from "./utils";

import { tolerance } from "./utils";

/**
* Calculates the power of a given base raised to an integer exponent
Expand Down Expand Up @@ -50,20 +49,20 @@ import { Euler, tolerance } from "./utils";
* ```
*/

export function pow(base: number | string, exponent: number | string, percision: number | undefined = undefined, negate: boolean | undefined = false):string {
export function pow(base: number | string, exponent: number | string, precision: number | undefined = undefined, negate: boolean | undefined = false): string {

exponent = exponent.toString();
base = base.toString();

if(isExatclyZero(exponent)){
if (isExatclyZero(exponent)) {
return '1'
}

if(!exponent.includes('-') && isExatclyOne(exponent)){
if (!exponent.includes('-') && isExatclyOne(exponent)) {
return base
}

if(isExatclyZero(base) && exponent.includes('-') && isExatclyOne(exponent)){
if (isExatclyZero(base) && exponent.includes('-') && isExatclyOne(exponent)) {
throw Error('0^(-1) is undefined');
}

Expand All @@ -72,8 +71,8 @@ export function pow(base: number | string, exponent: number | string, percision:
const negativeBase = base.includes('-');
const isBase10 = compareTo(abs(base), '10') == 0;
const negativeBase10 = isBase10 && negativeBase;
const orderOrPercision = reciprical && compareTo(abs(exponent), '1') == -1 ? percision : Number(abs(exponent));
const recipricalPercision = isBase10 ? orderOrPercision : percision;
const orderOrprecision = reciprical && compareTo(abs(exponent), '1') == -1 ? precision : Number(abs(exponent));
const recipricalprecision = isBase10 ? orderOrprecision : precision;

let fractionalExponent = '1';
let result = '1';
Expand All @@ -85,7 +84,7 @@ export function pow(base: number | string, exponent: number | string, percision:

if (!isExatclyZero(remainder)) {

if(negativeBase && !negativeBase10){
if (negativeBase && !negativeBase10) {
negate = !negate
}

Expand Down Expand Up @@ -114,12 +113,12 @@ export function pow(base: number | string, exponent: number | string, percision:
}

result = multiply(result, fractionalExponent);
result = (percision) ? roundOff(result, percision) : result;
result = (reciprical) ? divide(1, result, recipricalPercision) : result;
result = (precision) ? roundOff(result, precision) : result;
result = (reciprical) ? divide(1, result, recipricalprecision) : result;
return (negate) ? stripTrailingZero(negateFn(result)) : stripTrailingZero(result);
};

export function nthRoot(x: number | string, n: number | string, percision = 8) {
export function nthRoot(x: number | string, n: number | string, precision = 8) {

x = x.toString();
n = n.toString();
Expand All @@ -128,56 +127,54 @@ export function nthRoot(x: number | string, n: number | string, percision = 8) {

let guess = '1';
let nMinusOne = subtract(n, 1);
let percisionMax = Number(multiply(percision + 1, 2));
let precisionMax = Number(multiply(precision + 1, 2));

let i = 0;
while (i < percisionMax) {
while (i < precisionMax) {

let newGuess = divide(add(stripTrailingZero(divide(x, pow(guess, nMinusOne), percisionMax)), multiply(guess, nMinusOne)), n, percisionMax);
let newGuess = divide(add(stripTrailingZero(divide(x, pow(guess, nMinusOne), precisionMax)), multiply(guess, nMinusOne)), n, precisionMax);

if (lessThan(newGuess, tolerance(percision))) {
return stripTrailingZero(roundOff(newGuess, percision + 1))
if (lessThan(newGuess, tolerance(precision))) {
return stripTrailingZero(roundOff(newGuess, precision + 1))
}

guess = stripTrailingZero(newGuess);

i++;
}

return stripTrailingZero(roundOff(guess, percision + 1))
return stripTrailingZero(roundOff(guess, precision + 1))
}

export function sqRoot(base: string|number, percision = 32) {
percision = Math.max(percision, 32);
return nthRoot(base, 2, percision);
export function sqRoot(base: string | number, precision = 32) {
precision = Math.max(precision, 32);
return nthRoot(base, 2, precision);
}

export function cbRoot(base: string|number, percision = 32) {
percision = Math.max(percision, 32);
return nthRoot(base, 3, percision);
export function cbRoot(base: string | number, precision = 32) {
precision = Math.max(precision, 32);
return nthRoot(base, 3, precision);
}

export function root4(base: string|number, percision = 32) {
percision = Math.max(percision, 32);
return sqRoot(sqRoot(base, percision), percision);
export function root4(base: string | number, precision = 32) {
precision = Math.max(precision, 32);
return sqRoot(sqRoot(base, precision), precision);
}

export function root5(base: string|number, percision = 32) {
percision = Math.max(percision, 32);
return nthRoot(base, 5, percision);
export function root5(base: string | number, precision = 32) {
precision = Math.max(precision, 32);
return nthRoot(base, 5, precision);
}

export function root10(base: string|number, percision = 32) {
percision = Math.max(percision, 32);
return sqRoot(root5(base, percision), percision);
export function root10(base: string | number, precision = 32) {
precision = Math.max(precision, 32);
return sqRoot(root5(base, precision), precision);
}

export function exp(exponent: number | string){
return pow(Euler(32),exponent)
}

function validate(oparand: string) {
if (oparand.includes('.')) {
throw Error('Root base of non-integers not supported');
}
}


Empty file added src/trig.spec.ts
Empty file.
Loading

0 comments on commit 53de852

Please sign in to comment.