number
number
「數」或「數量」或「數值」或「數字」。例如1 2 3 4 5。
large number(big number)
「大數」。很大的數量。例如12345431848949513953123。
number運算
operation (noun) operation (verb) result (noun) --- --------------------- ------------------- ----------------- + addition 加法 add 加 sum 和 − subtraction 減法 subtract 減 difference 差 × multiplication 乘法 multiply 乘 product 積 ÷ division 除法 divide 除 quotient 商 mod modulo 模 --- 模 remainder 餘 ^ exponentiation 乘方 exponentiate 乘方 power 冪 √‾ --- 開方 --- 開方 root 根 log --- 取對數 --- 取對數 logarithm 對數 ∑ summation 連加 --- 連加 sum 總和 ∏ --- 連乘 --- 連乘 product 連乘積
number資料結構
要存放這麼大的數量,有個好方法——使用陣列。
陣列有很多格子,一個格子存一個數字。1000格的int陣列,可以存1000個位數!
我們習慣將低位數放在索引值較小的位置,高位數放在索引值較大的位置。比如存放680468975231245:
₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ... _____________________________________ |5|4|2|1|3|2|5|7|9|8|6|4|0|8|6| | | | ... ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
每個人對陣列的思考模式不一樣,像這裡就是由左至右的,另外也有人覺得陣列是由右至左、由上至下、彎彎曲曲的、……。要怎麼思考都是可以的,一以貫之就好囉。
陣列右端的空格,通常設成0,運算的時候比較方便。
scan
從字串中讀取大數。
簡單起見,此處假設大數絕對不是負數。
在螢幕上印出大數。
如果這個大數有可能是零,就得加個幾行程式碼。
comparsion <
兩個大數比較大小。
addition +
大數加法的粗略程式碼。
大數的運算有個有趣的地方,就是運算時不用立即進位,可以後來再一口氣進位。
UVa 10035
subtraction −
大數減法的粗略程式碼。
multiplication ×
大數乘法的粗略程式碼。我一定要強調它是粗略的。
大數乘以int變數,比較容易一些。
UVa 338 10106
division ÷
大數除法可以直接使用長除法。
商數範圍是0到9,所以必須一一嘗試。可以利用高位數相除來估計商數的範圍,便不必一一嘗試。
大數除以int變數,比較容易一些。
square root √‾
大數平方根可以直接使用直式開方法。
UVa 10023 10606
改進資料結構
₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ... _____________________________________ |5|4|2|1|3|2|5|7|9|8|6|4|0|8|6| | | | ... ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
一格只存一個數字,有點浪費。
int的數值範圍約為10位數,一格能夠存入9位數。1000格的int陣列,從原來的1000位數,搖身一變成為9000位數。如果想要存入1000位數,僅僅需要112格。這個新想法,大幅降低空間用量,也大幅降低運算次數。
₀ ₁ ₂ ₃ _________________________________ |975231245| 680468| | ... ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
不過,如果一格存了很多位數,會對運算造成什麼影響呢?
一、進位:如果一格存了9個位數,那麼每到10⁹才能進位。
二、進位溢位:進位讓鄰格的數字增加。如果鄰格原本就有一個很大的數字,就可能產生溢位。
三、乘法溢位:乘法是兩格相乘,添加到另一格。如果兩格都存了9個位數,相乘之後至少17個位數,遠遠超過int的上限。
除此之外還要考慮除法、平方根。雖然問題重重,但是並不代表一格還是只能存一個數字。稍微存個幾位數,應該不成問題吧?這些問題就留給大家思考。
UVa 288 10220 10814 10925 748
number base
記載數量
想要記載一個數量,最直觀的方式是:一個符號、重複數次。
♥ ♦♦ ☁☁☁ ★★★★★★★★★★★★★★★★★★
第一個技術:分堆
一個個數,太花時間。為了節省時間,可以嘗試分堆。最常見的分堆方式,是十個一堆。如果有很多堆,那麼十堆再合成一大堆;如果有很多大堆,那麼十大堆再合成一大大堆;以此類推。
hard way: ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ easy way: ★★★★★★★★★★ ★★★★★★★★★★ ★ ★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★ ★★★★★★★★★★
以此類推的過程,我們習慣採用固定數量,這個數量稱作「底數base」或「基數radix」。例如上例的底數就是十。
然而也有例外。例如時間:六十秒一分、六十分一時、二十四時一日,底數不是固定數量。
第二個技術:命名
一個個數,太花時間。為了節省時間,可以替每種數量取不一樣的名字;換句話說,用不一樣的符號代替每種數量。
長長一串數量,變成短短一個符號,人生充滿歡樂!
這些符號稱作「數字digit」。
同時使用第一個技術和第二個技術:位數
越多符號,越難背誦。你能想像背誦一百種符號代替一百種數量嗎?符號還是少點好。
解法是同時使用第一個技術和第二個技術,令符號數量等於底數。例如底數是十,可以使用0123456789等十個符號。當數量大於等於十,十個形成一堆,記載在左邊一點的位置,變成10。當數量累積十堆,十堆形成一大堆,記載在更左邊一點的位置,變成100。這是地球上最流行的記載方式。
除了替每一種數量取名字,有些語言還會替每一種數量級取名字,讓數字之間穿插數量級符號。這是題外話。
132 英文:one hundred thirty-two (hundred是數量級的符號) 中文:一百三十二 (百、十是數量級的符號)
選擇底數
我們可以選擇自己喜歡的底數。底數不能是零、不能是一。底數是二,稱作「二進位」,使用01兩個符號。底數是三,稱作「三進位」,使用012三個符號。底數是十六,稱作「十六進位」,使用0123456789ABCDEF十六個符號。底數超過三十六,那麼必須額外引入一些符號,才夠用。
底數寫於數字的右下角,用括號包住。
101₍₂₎ 二進位,數字是101 73F₍₁₆₎ 十六進位,數字是73F
同樣的數量,使用不同的底數,往往得到不同的數字。
★★★★★★★★★★★★★★★★★★ 10010₍₂₎ ★★★★★★★★★★★★★★★★★★ 18₍₁₀₎ ★★★★★★★★★★★★★★★★★★ 12₍₁₆₎
同樣的數字,使用不同的底數,往往得到不同的數量。
11₍₂₎ ★★★ 11₍₁₀₎ ★★★★★★★★★★★ 11₍₁₆₎ ★★★★★★★★★★★★★★★★★
選定底數,數字變數量(scan)
C語言當中的atoi()字串轉整數函式,其實就是「選定底數10,把數字變成數量」。
選定底數,數量變數字(print)
更換底數(進制轉換)
10010₍₂₎ = ?₍₁₆₎
令數量維持相等,給定原數字、原底數、新底數,求新數字。
演算法和程式碼交給讀者思考!
UVa 343 344 355 377 389 446 448 575 594 619 636 10019 10469 10473 11005 11121
polynomial
polynomial
「多項式」。變數的各種次方、乘上倍率、通通相加。
2x³ + 0x² - 4x¹ + 8x⁰
求值(Horner's rule)
已知x、已知係數c₀ c₁ c₂ ...,求c₀x⁰ + c₁x¹ + c₂x² + ...。
一乘一加,得到答案。不需要次方運算。時間複雜度O(N)。
2x³ + 0x² - 4x¹ + 8 = (((((2 ⋅ x) + 0) ⋅ x) - 4) ⋅ x) + 8
求係數【尚無正式名稱】
已知x、已知c₀x⁰ + c₁x¹ + c₂x² + ...,求係數c₀ c₁ c₂ ...。
答案無限多種。其中一種答案是求值演算法顛倒做。
一模一除,得到答案。不需要次方運算。時間複雜度O(N)。
一個數字可以改寫成一個多項式
10010₍₂₎ ---> 1x⁴ + 0x³ + 0x² + 1x¹ + 0x⁰ (x = 2) 18₍₁₀₎ ---> 1x¹ + 8x⁰ (x = 10) 73F₍₁₆₎ ---> 7x² + 3x¹ + 15x⁰ (x = 16)
在數學家眼中,底數可以藉由多項式一以貫之。
「選定底數,數字變數量」就是「求值」。
「選定底數,數量變數字」就是「求係數」。
大數就是多項式,x代入10。大數運算就是多項式運算。
十進位、二進位、八進位、十六進位,進位制就是多項式,x代入各種底數。
luogu P5248
延伸閱讀:益智問題
以身試毒:
兩步猜出多項式的係數:
numeral system
春雨驚春清穀天,夏滿芒夏暑相連,
秋處露秋寒霜降,冬雪雪冬小大寒。《二十四節氣歌》
number type
數量種類
operation (noun) example --- --------------------------------- ----------- ℕ natural numbers 自然數 0 1 2 3 4 ℤ integers 整數 -2 -1 0 1 2 ℚ rational numbers 有理數(分數) 1/3 0.123 𝔸 algebraic numbers 代數數 √2 ∛2 --- --------------------------------- ----------- ℝ real numbers 實數 π e ℂ complex numbers 複數 √-1 1+2𝑖
數量與運算
1 + 2 = ☐。自然數加法運算。數一數手指就行了。
☐ + 2 = 3。自然數加法反運算。等量公理(移項)就行了。
那麼☐ + 2 = 1呢?答案不是自然數。旅途就此開始。
數量種類(基於運算)
正運算補滿數域,反運算拓展數域。
數量的基礎是自然數。自然數裝備加法得到所有自然數。整數裝備乘法得到所有整數。有理數裝備自然數乘方得到所有有理數。
數量的基礎是自然數。自然數裝備減法得到整數。整數裝備除法得到有理數。有理數裝備自然數開方得到代數數。
數量種類(基於幾何)
實數是有理數之間相鄰相連的數。用來簡化有理數的計算。
複數是代數數之間相鄰相連的數。用來簡化代數數的計算。
數量變幾何之後,數量獲得長度、角度,方便理解數量的計算。
實數數線real line:直角座標系。
實數 ⇨ 點 實數長度 ⇨ 點到原點的距離 實數加法 ⇨ 點的座標相加(位移) 實數乘法 ⇨ 點的長度相乘(縮放)、點的方位負負得正(鏡射)
複數平面complex plane:直角座標系、極座標系兩者合體。
複數 ⇨ 點 複數長度 ⇨ 從原點出發的直線距離 複數角度 ⇨ 從實軸出發的逆時針夾角 複數加法 ⇨ 點的座標相加(位移) 複數乘法 ⇨ 點的長度相乘(縮放)、點的角度相加(旋轉)
複數總是可以化作a+b𝑖的形式。實數a b、虛數𝑖 = √-1。
複數乘法變點的長度相乘、角度相加,使之循環繞圈,這是古人一致推薦的方式。由於很好用,從此沒有採用其他方式。
UVa 10378
程式語法
注意到,由於數值精確度的緣故,這些語法沒有完全符合數學家的定義!雖說如此,普通情況下已經足夠堪用了!
自然數:unsigned char、unsigned short、unsigned int、unsigned long long。記憶體使用量、數值範圍有所差異。
整數:char、short、int、long long。
有理數:C/C++程式語言沒有對應的語法。
代數數:C/C++程式語言沒有對應的語法。
實數:float、double、long double。
複數:complex,需要引入標頭檔
函式庫