Skip to content

Commit

Permalink
Merge pull request #99 from riccardofano/common-denominator
Browse files Browse the repository at this point in the history
Add query param to convert fractions to common denominator
  • Loading branch information
riccardofano authored Feb 13, 2024
2 parents f1ad8a7 + f12831b commit 476a9af
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 2 deletions.
49 changes: 49 additions & 0 deletions core/commonDenominator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Fraction from 'fraction.js'

function gcd(a: number, b: number): number {
a = Math.abs(a)
b = Math.abs(b)

if (b > a) {
const temp = a
a = b
b = temp
}

while (true) {
a %= b
if (a === 0) {
return b
}
b %= a
if (b === 0) {
return a
}
}
}

function lcm(a: number, b: number): number {
return Math.abs(a * b) / gcd(a, b)
}

export function toCommonDenominator(list: Record<string, string>) {
if (Object.entries(list).length < 2) {
return
}

let denominator = 1
for (const str of Object.values(list)) {
const current = new Fraction(str)
denominator = lcm(denominator, current.d)
}

for (const [key, value] of Object.entries(list)) {
const current = new Fraction(value)
const difference = denominator / current.d

current.n *= difference
current.d = denominator

list[key] = current.toFraction(false)
}
}
115 changes: 115 additions & 0 deletions core/tests/commonDenominator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { toCommonDenominator } from '../commonDenominator'

test('Should handle 1 number in the list', () => {
const list = {
'0': '1/3',
}

toCommonDenominator(list)

expect(list['0']).toBe('1/3')
})

test('Should handle 2 numbers in the list', () => {
const list = {
'0': '1/3',
'1': '1/2',
}

toCommonDenominator(list)

expect(list['0']).toBe('2/6')
expect(list['1']).toBe('3/6')
})

test('Should handle 3 numbers in the list', () => {
const list = {
'0': '1/3',
'1': '1/2',
'2': '1/6',
}

toCommonDenominator(list)

expect(list['0']).toBe('2/6')
expect(list['1']).toBe('3/6')
expect(list['2']).toBe('1/6')
})

test('Should handle a lot of numbers in the list', () => {
const list = {
'0': '1/3',
'1': '1/2',
'2': '1/6',
'3': '1/17',
'4': '1/5',
'5': '1/10',
'6': '1/70',
'7': '1/32',
}

toCommonDenominator(list)

expect(list['0']).toBe('19040/57120')
expect(list['1']).toBe('28560/57120')
expect(list['2']).toBe('9520/57120')
expect(list['3']).toBe('3360/57120')
expect(list['4']).toBe('11424/57120')
expect(list['5']).toBe('5712/57120')
expect(list['6']).toBe('816/57120')
expect(list['7']).toBe('1785/57120')
})

test('Should handle 1 correctly', () => {
const list = {
'0': '1',
'1': '1/2',
'2': '1/6',
}

toCommonDenominator(list)

expect(list['0']).toBe('6/6')
expect(list['1']).toBe('3/6')
expect(list['2']).toBe('1/6')
})

test('Should be able to return whole numbers', () => {
const list = {
'0': '1',
'1': '1',
}

toCommonDenominator(list)

expect(list['0']).toBe('1')
expect(list['1']).toBe('1')
})

test('Should handle 0 correctly', () => {
const list = {
'0': '0',
'1': '1/2',
'2': '1/6',
}

toCommonDenominator(list)

expect(list['0']).toBe('0/6')
expect(list['1']).toBe('3/6')
expect(list['2']).toBe('1/6')
})

test('Should be able to handle big numbers', () => {
const list = {
'0': '1/9',
'1': '1/54',
'2': '1/47',
}

toCommonDenominator(list)

expect(list['0']).toBe('282/2538')
expect(list['1']).toBe('47/2538')
expect(list['2']).toBe('54/2538')
})
8 changes: 8 additions & 0 deletions pages/api/inheritance.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { NextApiRequest, NextApiResponse } from 'next'

import { calculateInheritance } from '../../core/inheritance'
import { toCommonDenominator } from '../../core/commonDenominator'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).send({ error: 'Method not allowed' })
}

if (req.headers['content-type'] !== 'application/json') {
return res.status(400).send({ error: 'Content type not allowed' })
}
Expand All @@ -13,6 +16,11 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {

try {
const result = calculateInheritance(req.body)

if (req.query['denominatorecomune'] === 'true') {
toCommonDenominator(result)
}

return res.json(result)
} catch (error) {
return res.status(500).send({ error: 'Failed to parse body' })
Expand Down
7 changes: 7 additions & 0 deletions pages/api/inverted/inheritance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'

import { calculateInheritance } from '../../../core/inheritance'
import { defaultRoot, invertGraph } from '../../../core/invertGraph'
import { toCommonDenominator } from '../../../core/commonDenominator'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
Expand All @@ -14,6 +16,11 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const graph = invertGraph(defaultRoot(), req.body)
const result = calculateInheritance(graph)

if (req.query['denominatorecomune'] === 'true') {
toCommonDenominator(result)
}

return res.json(result)
} catch (error) {
return res.status(500).send({ error: 'Failed to parse body' })
Expand Down
15 changes: 13 additions & 2 deletions pages/api/patrimony.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import { NextApiRequest, NextApiResponse } from 'next'

import { calculatePatrimony } from '../../core/patrimony'
import { toCommonDenominator } from '../../core/commonDenominator'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') return res.status(405).send({ error: 'Method not allowed' })
if (req.headers['content-type'] !== 'application/json')
if (req.method !== 'POST') {
return res.status(405).send({ error: 'Method not allowed' })
}

if (req.headers['content-type'] !== 'application/json') {
return res.status(400).send({ error: 'Content type not allowed' })
}

try {
const result = calculatePatrimony(req.body)

if (req.query['denominatorecomune'] === 'true') {
toCommonDenominator(result)
}

return res.json(result)
} catch (error) {
return res.status(500).send({ error: 'Failed to parse body' })
Expand Down

0 comments on commit 476a9af

Please sign in to comment.