改進《純數學教程(紀念版)》中的根式
人民郵電出版社圖靈公司準備重新出版《純數學教程(紀念版)》。我於 2013 年 10 月寫了一篇文章“《純數學教程(紀念版)》中的根式”,說:書中的根式裡面都有不必要的括號。
現在我們來去掉這些不必要的括號。這本書是使用 LaTeX 排版的,第 31 頁第 32 題的第 1 個根式的 TeX 程式碼如下:
\[
\sqrt {\left( {\sqrt[3]{5} - \sqrt[3]{4}} \right)} =
\frac{1}{3}\left( {\sqrt[3]{2} + \sqrt[3]{20} -
\sqrt[3]{{25}}}\right),
\]
去掉不必要的括號後變為:
\[
\sqrt { {\sqrt[3]{5} - \sqrt[3]{4}} } =
\frac{1}{3}\left( {\sqrt[3]{2} + \sqrt[3]{20} -
\sqrt[3]{{25}}}\right),
\]
第 2 個根式:
\[
\sqrt[\mbox{\raisebox{0.8ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\sqrt[3]{2} - 1} \right)}=
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\frac{1}{9}} \right)}-
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\frac{2}{9}} \right)}+
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\frac{4}{9}} \right)},
\]
去掉不必要的括號後變為:
\[
\sqrt[\mbox{\raisebox{0.8ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\sqrt[3]{2} - 1} }=
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\frac{1}{9}} }-
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\frac{2}{9}} }+
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\frac{4}{9}} },
\]
我寫了一個 C# 程式來完成這個任務,執行結果如下:
$ mcs sqrttransformer.cs && ./sqrttransformer.exe
5 3 ../ch00.tex
273 41 ../ch01.tex
109 50 ../ch02.tex
58 34 ../ch03.tex
52 10 ../ch04.tex
53 36 ../ch05.tex
216 156 ../ch06.tex
70 61 ../ch07.tex
101 62 ../ch08.tex
112 75 ../ch09.tex
59 46 ../ch10.tex
7 7 ../ch99.tex
1115 581 Total
$
可以看出,全書共有 1115 個根式(包含巢狀的根式),其中有 581 個根式需要去掉不必要的括號。第 6 章需要去掉不必要的括號的根式最多,有 156 個。
源程式如下:
1 using System;
2 using System.IO;
3
4 static class SqrtTransformer
5 {
6 static readonly string S = "\\sqrt", L = "\\left", R = "\\right";
7 static readonly string[] Ls = {"(","[","\\{",L+"(",L+"[",L+"\\{"};
8 static readonly string[] Rs = {")","]","\\}",R+")",R+"]",R+"\\}"};
9 static int n1 = 0, n2 = 0;
10
11 static string DeleteBracket(string s)
12 {
13 if (s.Length < 5 || s[0] != '{' || s[s.Length - 1] != '}') return s;
14 var i0 = 1; while (char.IsWhiteSpace(s, i0)) i0++;
15 for (var k = 0; k < Ls.Length; k++) {
16 if (!s.Substring(i0).StartsWith(Ls[k])) continue;
17 var i1 = s.IndexOf(Rs[k], i0 += Ls[k].Length);
18 if (i1 < 0) throw new Exception("Right bracket not found");
19 var i2 = i1 + Rs[k].Length; while (char.IsWhiteSpace(s, i2)) i2++;
20 if (i2 + 1 != s.Length) return s; // right bracket isn't most right
21 return Transform("{" + s.Substring(i0, i1 - i0) + "}");
22 }
23 return s;
24 }
25
26 static (int Left, int Right) GetBoundary(string s, int i)
27 {
28 for (i += S.Length; char.IsWhiteSpace(s, i); ) i++;
29 if (s[i] == '[') { while (s[i] != ']') i++; i++; }
30 while (char.IsWhiteSpace(s, i)) i++; int i0;
31 if (s[i0 = i] != '{') return (i, i); //TODO: s[i] == '\\'
32 for (var n=1; n>0;) if (s[++i]=='{') n++; else if (s[i]=='}') n--;
33 return (i0, i); // s[i0] == '{' && s[i] == '}'
34 }
35
36 static string Transform(string s)
37 {
38 var t = new System.Text.StringBuilder();
39 for (int j, i = 0; i < s.Length; i++) {
40 if ((j = s.IndexOf(S, i)) < 0) { t.Append(s.Substring(i)); break; }
41 var (b, d) = GetBoundary(s, j); t.Append(s.Substring(i, b - i));
42 string s2, s1 = s.Substring(b, (i = d) - b + 1);
43 t.Append(s2 = DeleteBracket(s1)); n1++; if (s1 != s2) n2++;
44 }
45 return t.ToString();
46 }
47
48 static void Main()
49 {
50 int i1 = 0, i2 = 0;
51 foreach (var file in Directory.GetFiles("..", "ch??.tex")) {
52 File.WriteAllText(file, Transform(File.ReadAllText(file)));
53 Console.WriteLine("{0,4} {1,3} {2}", n1 - i1, n2 - i2, file);
54 i1 = n1; i2 = n2;
55 }
56 Console.WriteLine("{0,4} {1,3} Total", n1, n2);
57 }
58 }
簡要說明:
- 第 51 行的 foreach 迴圈遍歷全書各章(ch00.tex, ch01.tex, ...)。
- 第 52 行的 File.ReadAllText 方法把某一章全部讀入記憶體。
- 然後呼叫 Transform 方法進行轉換(去掉不必要的括號)。
- 接著呼叫 File.WriteAllText 方法把這一章寫回 ch??.tex 檔案。
- 第 36 至 46 行的 Transform 方法執行轉換。主要是查詢 "\sqrt",然後呼叫 GetBoundary 方法找出其後的以 '{' 和 '}' 表示的左右邊界,再去掉其中的不必要的括號。
- 第 26 至 34 行的 GetBoundary 方法尋找 "\sqrt" 的左右邊界。
- 第 29 行跳過 "[...]"(對應於開平方以外的情況)。
- 第 31 行對應被開方數是單個符號的情況。其中有可能是 \Delta 這樣用多個字元表示的單個符號,但是對我們的目的沒有影響,為簡單起見,直接定界為 \ 就行了。
- 第 32 行定界 "{...}" 的情況,其中允許有巢狀的 "{}"。
- 第 11 至 24 行的 DeleteBracket 方法刪除不必要的括號。
- 第 16 行判斷根式中是不是以左括號開頭。
- 第 17 行尋找匹配的右括號。
- 第 18 行處理找不到匹配的右括號的情況。
- 第 20 行處理右括號後面不是緊接著右邊界的情況,此時這對括號是必要的,不能刪除。
- 第 21 行遞迴呼叫 Transform 方法以刪除巢狀的根式中的不必要的括號。
如果需要正確處理被開方數是 \Delta 這樣的情況,可以把第 31 行替換為:
if (s[i0 = i] != '{') {
if (s[i] != '\\') return (i, i);
for (i0 = i++; char.IsLetter(s, i); ) i++;
return (i0, i - 1);
}
相關文章
- 《純數學教程(紀念版)》中的根式
- 用數學演算法排布911紀念碑上的姓名演算法
- 改進版的python求解數獨Python
- 紀念即將逝去的nosqlSQL
- 我的創作紀念日
- 免費線上戀愛紀念日、結婚紀念日計算器
- 最後的紀念---linuxGL(轉)Linux
- 紀念入坑隨筆
- 紀念皮拉內西:探索遊戲中的無限之境遊戲
- OMG !Gopher China 限量版紀念衫!他來了!Go
- 紀念我曾經的 Java 知識Java
- 索泰970至尊紀念版評測 壕氣沖天賀新年
- 紅米k30s至尊紀念版和小米10pro的區別
- 華碩GTX980紀念版評測 如此才叫真敗家
- win10純淨版系統中安裝沒有數字簽名驅動的教程Win10
- 紀念程式設計師施凡程式設計師
- 關於《Python基礎教程第二版》中4-1程式碼的改進Python
- 改變數學的命運——《計算進化史》變數
- 為慶祝週年紀念日,Win10版《我的世界》將支援OculusRiftWin10
- 錘子手機週年紀念版正式釋出:售價2480元
- 小米Note黑色紀念版釋出 限量3萬套售價2499元
- 基於 Angular 開發的 紀念日計算工具Angular
- 紀念DedeCMS創始人IT柏拉圖先生
- Swift 4.1 中的 Codable 改進Swift
- Python學習筆記(同時紀念自己的第一張思維導圖)Python筆記
- 對Boost庫中的數值到字串的轉換的改進 (轉)字串
- 查詢數N二進位制中1的個數(JS版 和 Java版)JSJava
- 入園第一天,聊作紀念
- 一切只為效能!名人堂十週年紀念版顯示卡正式釋出
- 粒子群演算法中對於學習因子的改進演算法
- win10純淨版怎麼安裝步驟_windows10純淨版安裝教程Win10Windows
- 改進版glide golang版本控制IDEGolang
- 11.4 - ? 改題紀要
- 把時間花在“經典”上——《C++程式設計語言(特別版):十週年中文紀念版》C++程式設計
- [下載]《看雪精華20週年紀念版》釋出!(含看雪論壇精華20)
- 提高學習改進記憶的科學方法
- shell的引數和指令碼流程改進指令碼
- 【翻譯】.NET 5中的效能改進