0%

優雅的單位轉換公式與推導

前言

單位轉換是多數系統中會碰到的課題,單純兩個單位之間的轉換還算容易,而多個單位的轉換就有點困難。以「速度」來說,在 m/s, mphkm/h 等數種單位之間互相轉換,排列組合就多達九種以上;而「貨幣」幾乎是每一個國家一種單位,需要在更多單位之間做轉換。如何寫出易於維護可擴展的單位轉換程式碼是非常重要的,這篇文章帶領讀者從數學角度出發,一步步推導出單位轉換公式並將其化為最簡。

直接的做法

以「速度」為例,m/s, mphkm/h 三個單位若需要互相轉換,最直接且暴力的做法是建立一個表記錄下每個單位之間的轉換因子,轉換時只需將原本的值乘以轉換因子 (factor),即可得到進行單位轉換後的數值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const unitFactors = {
'm/s': {
'm/s': 1,
'mph': 2.23693629,
'km/h': 3.6,
},
'mph': {
'm/s': 0.44704,
'mph': 1,
'km/h': 1.609344,
},
'km/h': {
'm/s': 0.277777778,
'mph': 0.621371192,
'km/h': 1,
},
}

function unitConvert(value, from, to) {
return value * unitFactors[from][to]
}

console.log(unitConvert(1, 'km/h', 'mph')) // 0.621371192

缺點

  1. 很多重複的資料:例如 unitFactors['m/s']['mph'] 其實就等於 1/unitFactors['mph']['m/s']

  2. 難以擴增:若要增加一個單位例如 ft/s,就要大幅改動轉換因子表如下所示,造成開發者的負擔

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    const unitFactors = {
    'm/s': {
    ..., // (ellipsis)
    'ft/s': 3.28084,
    },
    'mph': {
    ..., // (ellipsis)
    'ft/s': 1.466667,
    },
    'km/h': {
    ..., // (ellipsis)
    'ft/s': 0.911344,
    },
    'ft/s': {
    'm/s': 0.3048,
    'mph': 0.681818,
    'km/h': 1.09728,
    'ft/s': 1,
    }
    }

推導單位轉換公式

為了避免之後要償還技術債,不如現在就將單位轉換過程進行簡化。簡化的方式有很多種,這裡會透過數學推導來得到好用的單位轉換公式。

參數說明:

  • $v_1$:現在的值。
  • $u_1$:現在的單位。
  • $v_2$:單位轉換後的值。
  • $u_2$:轉換後的單位。
  • $f_{12}$:單位由 $u_1$ 轉換為 $u_2$ 時,所需乘的轉換因子。
  • $u_0$:基底單位。
  • $f_{01}$:單位由 $u_0$ 轉換為 $u_1$ 時,所需乘的轉換因子。
  • $f_{02}$:單位由 $u_0$ 轉換為 $u_2$ 時,所需乘的轉換因子。

可列出方程式

我們的目標就是算出 $v_2$

這時我們知道單位轉換的公式為 $v_1$ 乘以 $u_1/u_2$,將分數部分上下同除一個基底單位 $u_0$

$u_0$ 用來作為轉換的一個中間單位,它可以是任何單位如 m/s, mphkm/h,接下來將會演示如何使用此公式

使用公式實作單位轉換

這裡選定 m/s 基底單位 $u_0$,先建立以 m/s 為基底單位的轉換因子表

1
2
3
4
5
const unitFactors = {
'm/s': 1,
'mph': 2.23693629,
'km/h': 3.6,
}

最後實作單位轉換函數

1
2
3
4
5
6
function unitConvert(value, from, to) {
// v1 * (f02 / f01)
return value * (unitFactors[to]/unitFactors[from])
}

console.log(unitConvert(1, 'km/h', 'mph')) // 0.6213711916666667

問題的改善

  1. 沒有重複的資料:重複的資料已經隱含在 $1/f_{01}$ 之中,因此不需要再多記倒數後的結果。

  2. 容易擴充的轉換因子表:若要多加一個單位例如 ft/s,只需增加一行

    1
    2
    3
    4
    const unitFactors = {
    ..., // (ellipsis)
    'ft/s': 3.28084,
    }
很高興能在這裡幫助到您,歡迎登入 Liker 為我鼓掌 5 次,或者成為我的讚賞公民,鼓勵我繼續創造優質文章。
以最優質的內容回應您的鼓勵