請輸入一次不定方程式 ax + by = c 的係數。下方的算式和輸入欄連動,直接修改其中的數字也能計算。變更「要求的解的範圍」,還可以只列出正整數解。
這個頁面可以做什麼
- 只要輸入整數係數 \(a,\ b,\ c\),就能求出滿足 \(ax + by = c\) 的整數數對 \(x,\ y\)(整數解)
- 當 \(c\) 不是 \(a\) 和 \(b\) 的最大公因數的倍數時,就沒有整數解。會顯示判定結果,也會說明為什麼沒有解
- 可以逐行查看輾轉相除法的除法表,以及把餘數倒推回去求特解的表
- 答案不只一組:會用 \(x = x_0 + \dfrac{b}{g}t,\ y = y_0 - \dfrac{a}{g}t\)(\(t\) 為整數)的一般解,以及代入不同 \(t\) 的整數解一覽表來呈現
- 可以只列出「正整數解」或「大於或等於 0 的整數解」。像「用 50 元和 80 元兩種票券湊出剛好 1,000 元,有哪些買法?」這類問題,可以直接解出來
這個計算有什麼用?
只用 50 元和 80 元兩種票券湊出剛好 1,000 元、只用兩種砝碼量出某個重量、只用固定長度的材料拼出剛好的長度。這類「組合固定大小的東西,剛好湊到目標」的問題,就是求 \(ax + by = c\) 的整數解。
張數和個數不能是負的,所以實際上要篩選出正整數解,才算得到答案。
只有 6 個裝和 10 個裝的盒子時,能不能剛好湊出訂購的個數,取決於 \(6x + 10y = c\) 有沒有大於或等於 0 的整數解。6 和 10 的最大公因數是 2,所以奇數個的訂單怎麼組合都湊不出來。
在食品或零件的裝箱作業中,看清「湊得出的個數」,直接關係到能不能接單、該準備哪些尺寸的盒子。
只用 5 公升和 3 公升的容器量出 4 公升,這個有名的問題對應的是 \(5x + 3y = 4\) 的整數解(\(x\)、\(y\) 是用正負號表示各個容器倒入和倒出的次數)。因為 \(\gcd(5,\ 3) = 1\),不用實際操作,從式子就能先判定:只要有這兩個容器,以 1 公升為單位的任何量都量得出來。
在實驗或烹飪時思考「只用手邊的器材,能不能做出需要的量」,用的正是這個數學。
支撐網路銀行和網路購物的 RSA 加密,在由公鑰的值 \(e\) 產生私鑰的值 \(d\) 時,要解 \(e d + \varphi k = 1\) 這個一次不定方程式(\(\varphi\) 是每把金鑰各自決定的整數)。這裡用的,就是和這個頁面相同的擴展輾轉相除法。
即使是好幾百位數的數,用這個方法也能瞬間解出來,這正是加密能夠實用的基礎之一。
生產每個用 \(a\) 公克材料的產品 A,和每個用 \(b\) 公克的產品 B,想把準備好的 \(c\) 公克材料剛好用完。這個計畫就是求 \(ax + by = c\) 大於或等於 0 的整數解。產品不能只做 0.5 個,所以答案一定要是整數。
像這樣處理「答案只能是整數的規劃問題」的領域稱為整數規劃,用在生產計畫、排班、配送規劃等方面。
公式與圖形
符號與用語解說
符號
| \(a,\ b\) | 乘在 \(x\) 和 \(y\) 前面的係數。表示已知的數時,習慣用字母表前面的字母 \(a,\ b,\ c\)。這個頁面中兩者都是整數。 | |
| \(c\) | 方程式等號右邊的常數,取自 constant(常數)的第一個字母。相當於「想湊出的總和」,它是不是最大公因數的倍數,決定了有沒有解。 | |
| \(x,\ y\) | 要求的未知數。用字母表後面的字母表示未知數,據說是笛卡兒推廣開來的寫法。這個頁面只把整數值當作答案。 | |
| \(\gcd(a,\ b)\) | 最大公因數 | \(a\) 和 \(b\) 的最大公因數,取自 greatest common divisor(最大的共同因數)的第一個字母。台灣的課本也常簡寫成 \((a,\ b)\)(最小公倍數則寫成 \([a,\ b]\))。 |
| \(g\) | 把最大公因數 \(\gcd(a,\ b)\) 簡寫的符號,取自 greatest(最大)的第一個字母。像一般解中的 \(\dfrac{b}{g}\)、\(\dfrac{a}{g}\) 一樣,用來避免式子變得太長。 | |
| \(x_0,\ y_0\) | 特解,也就是最先找到的一組整數解。右下角的 0 表示「作為基準的第 0 個解」。以它為起點,表示所有的整數解。 | |
| \(x_1,\ y_1\) | 把輾轉相除法倒推回去找到的一對整數,滿足 \(a x_1 + b y_1 = g\)。乘以 \(\dfrac{c}{g}\) 倍,就是特解 \((x_0,\ y_0)\)。 | |
| \(t\) | 只要是整數都可以的變數(參數),用來把所有整數解整合成一個式子。\(t\) 每代入一個整數,就出現另一組整數解。 | |
| \(m\) | 表示「\(c\) 是 \(g\) 的幾倍」的整數。表示整數的字母常用 \(m\)、\(n\)、\(k\),據說 \(m\) 來自 multiple(倍數)的第一個字母。能寫成 \(c = g \times m\) 時才有整數解,而且只有這個時候才有。 | |
| \(q\) | 除法的商,取自 quotient(商)的第一個字母。在輾轉相除法的表中,相當於 \(13 = 5 \times 2 + 3\) 的 \(2\)。 | |
| \(r\) | 除法的餘數,取自 remainder(餘數)的第一個字母。在輾轉相除法的表中,相當於 \(13 = 5 \times 2 + 3\) 的 \(3\)。這個餘數變成 0 時,計算就結束了。 | |
| \(\geq\) | 大於或等於 | 表示「左邊大於或等於右邊」的不等號。\(x \geq 1\) 的意思是「\(x\) 大於或等於 1」。反過來的「小於或等於」寫成 \(\leq\)。 |
用語
| 一次不定方程式 | 像 \(ax + by = c\) 這樣,有兩個未知數卻只有一個式子的一次方程式。「不定」是指解不只一個;在實數範圍內,直線上的每一個點都是解。就算只看整數解,通常也有無限多組。 |
| 丟番圖方程式 | 只把整數解當作答案的方程式的總稱,名稱來自古希臘數學家丟番圖(Diophantus)。這個頁面處理的一次不定方程式,是其中最基本的一種。 |
| 整數解 | 滿足方程式的解當中,\(x\) 和 \(y\) 都是整數的解。求張數、個數、人數等「不可能有零頭的量」的問題,只有整數解才有意義。 |
| 特解 | 無限多組整數解當中,最先找到的一組。選哪一組都可以。以它為起點,用一般解的形式表示所有的解。 |
| 一般解 | 用整數 \(t\) 把所有整數解整合成一個式子來表示。\(t\) 每代入一個整數,就能取出另一組解。 |
| 最大公因數 | 能整除 2 個以上整數中每一個數的正整數當中,最大的那一個。在一次不定方程式中,這個值同時決定了「有沒有解」和「解與解的間隔」。 |
| 輾轉相除法 | 用大的數除以小的數,再換成「除數和餘數」這一組,一再重複這個操作來求最大公因數的方法,英文叫 Euclidean algorithm。餘數變成 0 時的除數就是最大公因數。這個方法記載在西元前 3 世紀左右的著作《幾何原本》中,被稱為世界上最古老的演算法。 |
| 擴展輾轉相除法 | 把輾轉相除法的除法算式由下往上依序代入,把最大公因數表示成 \(a x_1 + b y_1\) 形式的方法(英文 extended Euclidean algorithm),用來求一次不定方程式的特解。 |
| 貝祖等式 | 一定存在滿足 \(a x_1 + b y_1 = \gcd(a,\ b)\) 的整數 \(x_1,\ y_1\),這個定理也叫貝祖定理,名稱來自法國數學家貝祖(Bézout)。它是一次不定方程式可以解的根據。 |
| 互質 | 兩個整數的最大公因數是 1。例如 3 和 4 互質。\(\dfrac{a}{g}\) 和 \(\dfrac{b}{g}\) 一定互質,這正是「解會等距離排列」的關鍵。 |
| 倍數 | 把某個整數乘以整數所得的數。\(10\) 的倍數是 \(\dots,\ -20,\ -10,\ 0,\ 10,\ 20,\ \dots\)。0 和負數也算是倍數。 |
| 餘數 | 整數的除法中除不盡而剩下的數。\(13 \div 5\) 的商是 \(2\)、餘數是 \(3\)。輾轉相除法只靠這個餘數往下進行。 |
| 商 | 整數的除法中,表示「裡面有幾個除數」的整數。\(13 = 5 \times 2 + 3\) 的 \(2\) 就是商。 |
| 格子點 | 坐標平面上,\(x\) 坐標和 \(y\) 坐標都是整數的點,相當於方格紙上格線的交點。一次不定方程式的整數解,就是直線 \(ax + by = c\) 上的格子點。 |
| 參數 | 為了用一個式子表示所有的解而設的、可以自由變動的變數,這個頁面的 \(t\) 就是參數。 |
| 係數 | 寫在文字前面的數。\(3x\) 的 \(3\) 就是係數。沒有寫數字的 \(x\),係數視為 1。 |
| 不等式 | 像 \(t \geq 0\) 這樣,表示兩個值大小關係的式子。篩選正整數解時會用到。 |
建議先了解的基礎知識
為了能「真正理解意義」地使用這個頁面的計算,這裡整理了建議事先了解的基礎知識。
遇到卡關的地方,回到這張表的內容複習是最快的捷徑。
| 整數的除法與餘數(國小三年級~國中七年級,8~13 歲) |
|
| 因數、倍數與最大公因數(國小五年級~國中七年級,10~13 歲) |
|
| 代數式與一元一次方程式(國中七年級,12~13 歲) |
|
| 二元一次方程式與它的圖形(國中七年級,12~13 歲) |
|
| 不等式(國中七年級~高一,12~16 歲) |
|
| 分數的計算(國小五年級~國中七年級,10~13 歲) |
|
用 Excel 計算的方法
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 等號右邊的常數 c | 1000 |
| 最大公因數 g | =GCD(B1,B2) |
| c 除以 g 的餘數 | =MOD(B3,B4) |
| 有沒有整數解 | =IF(B5=0,"有整數解","沒有整數解") |
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 用輾轉相除法找到的 x1 | -3 |
| 用輾轉相除法找到的 y1 | 2 |
| a×x1 + b×y1 | =B1*B3+B2*B4 |
| 最大公因數 g | =GCD(B1,B2) |
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 等號右邊的常數 c | 1000 |
| 最大公因數 g | =GCD(B1,B2) |
| 特解 x0 | 4 |
| 特解 y0 | 10 |
| 整數 t | 1 |
| x = x0 + (b/g)×t | =B5+(B2/B4)*B7 |
| y = y0 − (a/g)×t | =B6-(B1/B4)*B7 |
| 驗算 a×x + b×y | =B1*B8+B2*B9 |
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 最大公因數 g | =GCD(B1,B2) |
| 特解 x0 | 4 |
| 特解 y0 | 10 |
| t 的下限(由 x ≥ 1) | =-INT((B4-1)/(B2/B3)) |
| t 的上限(由 y ≥ 1) | =INT((B5-1)/(B1/B3)) |
| 正整數解的組數 | =MAX(0,B7-B6+1) |
第 1 個表格是 50x + 80y = 1000 的例子,最大公因數是 10,1000 除以 10 的餘數是 0,所以會顯示「有整數解」。把這裡改成 1001,就會變成「沒有整數解」。
第 2 個表格用來確認把輾轉相除法倒推回去得到的 x1 = −3、y1 = 2,是否真的滿足貝祖等式。50× (−3) + 80×2 = 10,和最大公因數一致。
第 3 個表格是從一般解取出一組解的表格。t 輸入 1,得到 x = 12、y = 5,驗算那一列會回到 1000。請把 t 改成各種整數試試看。
第 4 個表格是篩選正整數解的表格。t 的下限是 0、上限是 1,所以知道正整數解有 2 組(t = 0 和 t = 1)。這兩個式子是 a 和 b 都是正數時用的,輸入負的係數時要注意不等號的方向會改變。
用 Google 試算表計算的方法
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 等號右邊的常數 c | 1000 |
| 最大公因數 g | =GCD(B1,B2) |
| c 除以 g 的餘數 | =MOD(B3,B4) |
| 有沒有整數解 | =IF(B5=0,"有整數解","沒有整數解") |
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 用輾轉相除法找到的 x1 | -3 |
| 用輾轉相除法找到的 y1 | 2 |
| a×x1 + b×y1 | =B1*B3+B2*B4 |
| 最大公因數 g | =GCD(B1,B2) |
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 等號右邊的常數 c | 1000 |
| 最大公因數 g | =GCD(B1,B2) |
| 特解 x0 | 4 |
| 特解 y0 | 10 |
| 整數 t | 1 |
| x = x0 + (b/g)×t | =B5+(B2/B4)*B7 |
| y = y0 − (a/g)×t | =B6-(B1/B4)*B7 |
| 驗算 a×x + b×y | =B1*B8+B2*B9 |
| x 的係數 a | 50 |
| y 的係數 b | 80 |
| 最大公因數 g | =GCD(B1,B2) |
| 特解 x0 | 4 |
| 特解 y0 | 10 |
| t 的下限(由 x ≥ 1) | =-INT((B4-1)/(B2/B3)) |
| t 的上限(由 y ≥ 1) | =INT((B5-1)/(B1/B3)) |
| 正整數解的組數 | =MAX(0,B7-B6+1) |
用 Python 計算的方法
from math import gcd
# ax + by = c 的係數(整數)
a, b, c = 50, 80, 1000
def extended_gcd(x, y):
# 擴展輾轉相除法:傳回 gcd,以及滿足 x*s + y*t = gcd 的 s, t
if y == 0:
return x, 1, 0
g, s, t = extended_gcd(y, x % y)
return g, t, s - (x // y) * t
g = gcd(a, b)
if c % g != 0:
print(f"{c} 不是 {g} 的倍數,所以沒有整數解")
else:
_, s, t = extended_gcd(a, b)
x0, y0 = s * (c // g), t * (c // g) # 特解(一組整數解)
step_x, step_y = b // g, a // g # x 的間隔和 y 的間隔
# 平移到 x 大於或等於 0 且最小,換成比較好看的特解
n = x0 // step_x
x0, y0 = x0 - n * step_x, y0 + n * step_y
print(f"特解:(x, y) = ({x0}, {y0})")
print(f"一般解:x = {x0} + {step_x}t, y = {y0} - {step_y}t(t 為整數)")
for k in range(-2, 3):
print(f" t = {k:2}: (x, y) = ({x0 + step_x * k}, {y0 - step_y * k})")
# 只取出正整數解(x >= 1 且 y >= 1)
t_low = -((1 - x0) // -step_x)
t_high = (y0 - 1) // step_y
print("正整數解:", [(x0 + step_x * k, y0 - step_y * k)
for k in range(t_low, t_high + 1)])
用 LaTeX 等數學式語言的寫法(可直接複製)
c = gcd(a, b) × m
c = \gcd(a, b) \times m
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<mrow>
<mi>c</mi>
<mo>=</mo>
<mi>gcd</mi><mo>(</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo>)</mo>
<mo>×</mo>
<mi>m</mi>
</mrow>
</math>
c = gcd(a, b) * m
Mod[c, GCD[a, b]] == 0
irem(c, igcd(a, b)) = 0;
mod(c, gcd(a, b)) == 0
c = gcd(a,b) × m
a·x₁ + b·y₁ = gcd(a, b)
a x_1 + b y_1 = \gcd(a, b)
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<mrow>
<mi>a</mi><msub><mi>x</mi><mn>1</mn></msub>
<mo>+</mo>
<mi>b</mi><msub><mi>y</mi><mn>1</mn></msub>
<mo>=</mo>
<mi>gcd</mi><mo>(</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo>)</mo>
</mrow>
</math>
a*x_1 + b*y_1 = gcd(a, b)
ExtendedGCD[a, b]
igcdex(a, b, x1, y1);
[g, x1, y1] = gcd(a, b);
a x_1 + b y_1 = gcd(a,b)
x = x₀ + (b/g)t, y = y₀ − (a/g)t
x = x_0 + \frac{b}{g} t, \quad y = y_0 - \frac{a}{g} t
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<mrow>
<mi>x</mi><mo>=</mo><msub><mi>x</mi><mn>0</mn></msub>
<mo>+</mo>
<mfrac><mi>b</mi><mi>g</mi></mfrac><mi>t</mi>
<mo>,</mo><mspace width="1em"/>
<mi>y</mi><mo>=</mo><msub><mi>y</mi><mn>0</mn></msub>
<mo>−</mo>
<mfrac><mi>a</mi><mi>g</mi></mfrac><mi>t</mi>
</mrow>
</math>
x = x_0 + (b/g)t, y = y_0 - (a/g)t
Solve[a x + b y == c, {x, y}, Integers]
isolve(a*x + b*y = c);
S = solve(a*x + b*y == c, [x y], 'Integer', true);
x = x_0 + (b/g)t, y = y_0 - (a/g)t
x₀ + (b/g)t ≥ 1 且 y₀ − (a/g)t ≥ 1
x_0 + \frac{b}{g} t \geq 1, \quad y_0 - \frac{a}{g} t \geq 1
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<mrow>
<msub><mi>x</mi><mn>0</mn></msub>
<mo>+</mo>
<mfrac><mi>b</mi><mi>g</mi></mfrac><mi>t</mi>
<mo>≥</mo><mn>1</mn>
<mo>,</mo><mspace width="1em"/>
<msub><mi>y</mi><mn>0</mn></msub>
<mo>−</mo>
<mfrac><mi>a</mi><mi>g</mi></mfrac><mi>t</mi>
<mo>≥</mo><mn>1</mn>
</mrow>
</math>
x_0 + (b/g)t >= 1 and y_0 - (a/g)t >= 1
Solve[a x + b y == c && x >= 1 && y >= 1, {x, y}, Integers]
isolve({a*x + b*y = c, x >= 1, y >= 1});
S = solve([a*x + b*y == c, x >= 1, y >= 1], [x y], 'Integer', true);
x_0 + (b/g)t ≥ 1, y_0 − (a/g)t ≥ 1
請 ChatGPT 幫忙計算的方法
你是數學(整數的性質)計算助理。請務必實際執行 Python 程式碼來進行下面的計算,並只以執行結果的數值作為回答的依據(不要用心算或推測回答)。 請求出一次不定方程式 50x + 80y = 1000 的整數解。 請分別列出下列內容: 1. 50 和 80 的最大公因數,以及 1000 是不是它的倍數 2. 輾轉相除法的除法算式(直到餘數為 0),以及倒推回去得到的、滿足 50×x1 + 80×y1 = 最大公因數 的 x1, y1 3. 特解 (x0, y0),以及一般解 x = x0 + (b/g)t, y = y0 − (a/g)t 4. x 和 y 都大於或等於 1 的所有整數解 請在 Python 中用 math.gcd 和擴展輾轉相除法精確計算,並列出計算所用的公式和執行結果的數值。
使用方法
-
1輸入數值在輸入欄中輸入要計算的數值
-
2計算按下「計算」按鈕
-
3查看結果計算結果會立即顯示。計算的思路和公式的解說,也都能在同一個頁面查看
DataChef 的特色
不需專業知識,操作直覺又簡單
無須登錄任何個人資料
按下「下載」後自動刪除檔案
無須標註來源出處
亦無須事先取得商用授權