Skip to content

Commit e533187

Browse files
committed
Improved convertUnit accuracy and precision
1 parent 6a91e83 commit e533187

4 files changed

Lines changed: 36 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
- `convertUnit` options `fromSystem` and `toSystem` are now case-insensitive.
13+
- `convertUnit` rounds results to 6 decimal places for more accurate conversions. Updated conversion factors with more precise values.
1314

1415
## [v2.0.0] - 2026-01-29
1516

src/constants.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,14 @@ export const unitsOfMeasure: UnitOfMeasureDefinitions = {
252252
plural: 'ounces',
253253
alternates: ['oz.'] satisfies string[],
254254
type: 'mass',
255-
conversionFactor: 28.3495,
255+
conversionFactor: 28.349523,
256256
},
257257
pound: {
258258
short: 'lb',
259259
plural: 'pounds',
260260
alternates: ['lb.', 'lbs', 'lbs.'] satisfies string[],
261261
type: 'mass',
262-
conversionFactor: 453.592,
262+
conversionFactor: 453.59237,
263263
},
264264

265265
// Volume units (conversion factor in ml)
@@ -268,7 +268,7 @@ export const unitsOfMeasure: UnitOfMeasureDefinitions = {
268268
plural: 'cups',
269269
alternates: ['c.', 'C'] satisfies string[],
270270
type: 'volume',
271-
conversionFactor: { us: 236.588, imperial: 284.131, metric: 250 },
271+
conversionFactor: { us: 236.58824, imperial: 284.13063, metric: 250 },
272272
},
273273
deciliter: {
274274
short: 'dl',
@@ -295,14 +295,14 @@ export const unitsOfMeasure: UnitOfMeasureDefinitions = {
295295
'fluid-oz',
296296
] satisfies string[],
297297
type: 'volume',
298-
conversionFactor: { us: 29.5735, imperial: 28.4131 },
298+
conversionFactor: { us: 29.57353, imperial: 28.413063 },
299299
},
300300
gallon: {
301301
short: 'gal',
302302
plural: 'gallons',
303303
alternates: ['gal.'] satisfies string[],
304304
type: 'volume',
305-
conversionFactor: { us: 3785.41, imperial: 4546.09 },
305+
conversionFactor: { us: 3785.4118, imperial: 4546.09 },
306306
},
307307
liter: {
308308
short: 'l',
@@ -323,28 +323,28 @@ export const unitsOfMeasure: UnitOfMeasureDefinitions = {
323323
plural: 'pints',
324324
alternates: ['pt.'] satisfies string[],
325325
type: 'volume',
326-
conversionFactor: { us: 473.176, imperial: 568.261 },
326+
conversionFactor: { us: 473.17647, imperial: 568.26125 },
327327
},
328328
quart: {
329329
short: 'qt',
330330
plural: 'quarts',
331331
alternates: ['qt.', 'qts', 'qts.'] satisfies string[],
332332
type: 'volume',
333-
conversionFactor: { us: 946.353, imperial: 1136.52 },
333+
conversionFactor: { us: 946.35295, imperial: 1136.5225 },
334334
},
335335
tablespoon: {
336336
short: 'tbsp',
337337
plural: 'tablespoons',
338338
alternates: ['tbsp.', 'T', 'Tbsp.', 'Tbsp', 'tablespoonful'] satisfies string[],
339339
type: 'volume',
340-
conversionFactor: { us: 14.787, imperial: 17.758, metric: 15 },
340+
conversionFactor: { us: 14.786765, imperial: 15, metric: 15 },
341341
},
342342
teaspoon: {
343343
short: 'tsp',
344344
plural: 'teaspoons',
345345
alternates: ['tsp.', 't', 'teaspoonful'] satisfies string[],
346346
type: 'volume',
347-
conversionFactor: { us: 4.929, imperial: 5.919, metric: 5 },
347+
conversionFactor: { us: 4.9289216, imperial: 5, metric: 5 },
348348
},
349349

350350
// Volume units without conversion factor (imprecise)

src/convertUnit.test.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,17 @@ describe('volume conversions', () => {
9393

9494
test('tablespoon to teaspoon (US)', () => {
9595
const result = convertUnit(1, 'tablespoon', 'teaspoon', { fromSystem: 'us' });
96-
expect(result).toBeCloseTo(3, 0);
96+
expect(result).toBe(3);
9797
});
9898

9999
test('pint to cup (US)', () => {
100100
const result = convertUnit(1, 'pint', 'cup', { fromSystem: 'us' });
101-
expect(result).toBeCloseTo(2, 0);
101+
expect(result).toBe(2);
102102
});
103103

104104
test('quart to pint (US)', () => {
105105
const result = convertUnit(1, 'quart', 'pint', { fromSystem: 'us' });
106-
expect(result).toBeCloseTo(2, 0);
106+
expect(result).toBe(2);
107107
});
108108

109109
test('fluid ounce to milliliter (US)', () => {
@@ -142,12 +142,12 @@ describe('length conversions', () => {
142142

143143
test('foot to inch', () => {
144144
const result = convertUnit(1, 'foot', 'inch');
145-
expect(result).toBeCloseTo(12, 0);
145+
expect(result).toBe(12);
146146
});
147147

148148
test('yard to foot', () => {
149149
const result = convertUnit(1, 'yard', 'foot');
150-
expect(result).toBeCloseTo(3, 0);
150+
expect(result).toBe(3);
151151
});
152152

153153
test('meter to centimeter', () => {
@@ -187,12 +187,12 @@ describe('fromSystem/toSystem relationships', () => {
187187
describe('same unit conversions', () => {
188188
test('cup US to cup US returns 1', () => {
189189
const result = convertUnit(1, 'cup', 'cup', { fromSystem: 'us', toSystem: 'us' });
190-
expect(result).toBeCloseTo(1, 5);
190+
expect(result).toBe(1);
191191
});
192192

193193
test('cup Imperial to cup Imperial returns 1', () => {
194194
const result = convertUnit(1, 'cup', 'cup', { fromSystem: 'imperial', toSystem: 'imperial' });
195-
expect(result).toBeCloseTo(1, 5);
195+
expect(result).toBe(1);
196196
});
197197

198198
test('cup US to cup Imperial', () => {
@@ -208,12 +208,12 @@ describe('fromSystem/toSystem relationships', () => {
208208
});
209209

210210
test('tablespoon US to tablespoon Imperial', () => {
211-
// US tbsp (14.787 ml) to Imperial tbsp (17.758 ml)
211+
// US tbsp (14.786765 ml) to Imperial tbsp (15 ml)
212212
const result = convertUnit(1, 'tablespoon', 'tablespoon', {
213213
fromSystem: 'us',
214214
toSystem: 'imperial',
215215
});
216-
expect(result).toBeCloseTo(14.787 / 17.758, 4);
216+
expect(result).toBeCloseTo(14.786765 / 15, 4);
217217
});
218218

219219
test('gallon Imperial to gallon US', () => {
@@ -248,16 +248,16 @@ describe('fromSystem/toSystem relationships', () => {
248248
fromSystem: 'metric',
249249
toSystem: 'metric',
250250
});
251-
expect(result).toBeCloseTo(1, 5);
251+
expect(result).toBe(1);
252252
});
253253

254254
test('tablespoon Imperial to tablespoon metric', () => {
255-
// Imperial tbsp (17.758 ml) to metric tbsp (15 ml)
255+
// Imperial tbsp (15 ml) to metric tbsp (15 ml)
256256
const result = convertUnit(1, 'tablespoon', 'tablespoon', {
257257
fromSystem: 'imperial',
258258
toSystem: 'metric',
259259
});
260-
expect(result).toBeCloseTo(17.758 / 15, 4);
260+
expect(result).toBeCloseTo(15 / 15, 4);
261261
});
262262
});
263263

@@ -276,12 +276,12 @@ describe('fromSystem/toSystem relationships', () => {
276276
});
277277

278278
test('US tablespoon to Imperial teaspoon', () => {
279-
// US tbsp (14.787 ml) to Imperial tsp (5.919 ml)
279+
// US tbsp (14.786765 ml) to Imperial tsp (5 ml)
280280
const result = convertUnit(1, 'tablespoon', 'teaspoon', {
281281
fromSystem: 'us',
282282
toSystem: 'imperial',
283283
});
284-
expect(result).toBeCloseTo(14.787 / 5.919, 3);
284+
expect(result).toBeCloseTo(14.786765 / 5, 3);
285285
});
286286

287287
test('Imperial pint to US cup', () => {
@@ -309,12 +309,12 @@ describe('fromSystem/toSystem relationships', () => {
309309
describe('units without multi-system factors', () => {
310310
test('gram to gram returns 1 regardless of system', () => {
311311
const result = convertUnit(1, 'gram', 'gram', { fromSystem: 'us', toSystem: 'imperial' });
312-
expect(result).toBeCloseTo(1, 5);
312+
expect(result).toBe(1);
313313
});
314314

315315
test('liter to liter returns 1 regardless of system', () => {
316316
const result = convertUnit(1, 'liter', 'liter', { fromSystem: 'imperial', toSystem: 'us' });
317-
expect(result).toBeCloseTo(1, 5);
317+
expect(result).toBe(1);
318318
});
319319

320320
test('pound to kilogram same regardless of system', () => {
@@ -360,7 +360,7 @@ describe('with additionalUOMs', () => {
360360
describe('unit spelling variations', () => {
361361
test('accepts short form units', () => {
362362
expect(convertUnit(1, 'c', 'ml')).toBeCloseTo(236.588, 2);
363-
expect(convertUnit(1, 'tbsp', 'tsp')).toBeCloseTo(3, 0);
363+
expect(convertUnit(1, 'tbsp', 'tsp')).toBe(3);
364364
expect(convertUnit(1, 'lb', 'g')).toBeCloseTo(453.592, 2);
365365
});
366366

@@ -370,7 +370,7 @@ describe('unit spelling variations', () => {
370370
});
371371

372372
test('accepts alternate spellings', () => {
373-
expect(convertUnit(1, 'T', 'tsp')).toBeCloseTo(3, 0);
373+
expect(convertUnit(1, 'T', 'tsp')).toBe(3);
374374
expect(convertUnit(1, 'lbs', 'g')).toBeCloseTo(453.592, 2);
375375
});
376376

@@ -425,7 +425,7 @@ describe('fromSystem and toSystem case-insensitivity', () => {
425425
fromSystem: 'METRIC' as UnitSystem,
426426
toSystem: 'metric',
427427
});
428-
expect(result).toBeCloseTo(1, 5);
428+
expect(result).toBe(1);
429429
});
430430

431431
test('mixed case produces same result as lowercase', () => {

src/convertUnit.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ export const convertUnit = (
121121
return null;
122122
}
123123

124+
// Same unit with same system - return value as-is
125+
if (fromUnitID === toUnitID && normalizedFromSystem === normalizedToSystem) {
126+
return value;
127+
}
128+
124129
const fromDef = mergedUOMs[fromUnitID];
125130
const toDef = mergedUOMs[toUnitID];
126131

@@ -138,5 +143,6 @@ export const convertUnit = (
138143
}
139144

140145
// Convert via base unit: value * fromFactor / toFactor
141-
return (value * fromFactor) / toFactor;
146+
const result = (value * fromFactor) / toFactor;
147+
return Math.round(result * 1e6) / 1e6;
142148
};

0 commit comments

Comments
 (0)