宋美蕓 謝佐杰


算法是高中數學中的重要內容,也是計算機科學的基礎,是連接問題與計算機程序語言之間的橋梁.若一元方程[f(x)=0]的左端函數[f(x)]不是關于x的多項式,那么我們就將類方程稱之為超越方程.超越方程一般沒有解析解,而只有數值解或近似解.求解超越方程近似解的方法有很多,而利用算法或者計算機程序語言來求解是最為簡便的一種方法.筆者結合一個實際應用問題,來談一談算法在求解超越方程中的應用.
問題:內江某玻璃廠的工人需要切割一塊如圖1所示的玻璃窗.若該窗戶的橫梁長為a、豎梁高為b、圓弧長為[l],為了能準確切割出這塊玻璃,工人必須知道此圓弧半徑[R].求該圓弧的半徑[R].
解析:如圖2,我們先作輔助線,將扇形擴充為一個完整的圓,連接AB、AO、BO,其中AO、BO為圓的半徑,[AB]為圓的一條弦,作弦[AB]的中垂線DO,則DO必過圓心且平分[∠AOB],令弧[AB]所對的圓心角∠AOB=θ(θ為弧度角),建立等式[l=θ?R],[sinθ2=a2+b22R],兩式聯立消去[θ]得[sinl2R=a2+b22R].該方程屬于超越方程,其中R是要求的未知量,該方程無法直接求解.一般,我們會采用常規方法,利用函數與方程的思想,令[fR=sinl2R][=a2+b22R],在同一個平面直角坐標中分別作出這兩個函數的圖象,于是兩圖象交點的橫坐標即為方程的解.此方法在理論上可行,但在實際操作中存在很大的困難.因為一般我們很難作出準確的圖形,并且通過畫圖得出的結果必然存在很大的誤差,所以這種方法并不是解答這個問題的最好方法.
我們可以轉換思路,利用算法來求解.首先,我們需要確保數據的準確性,將數據的單位設置為毫米,這樣可以將誤差控制在0.01毫米內.然后,我們可以從0.01毫米開始取值,讓R的值逐次遞增0.01,分別將其代入方程左邊和右邊的兩個等式[M=sinl2R]、[N=a2+b22R]中,并算出M和N的值,判斷|M-N|是否小于或等于0.001,其程序框圖如圖3所示.如果該值小于或等于0.001,我們就可以近似認為m=n,此時R的值就是方程的解.人工計算肯定需要很長的時間,但計算機可以以每秒上億次的計算速度來進行計算,得出結果所花的時間不足一秒,所以此方法可行.
該算法的關鍵是在R值遞增的過程中,判斷等式兩邊的差值是否小于或等于0.001.由于三角函數的正弦值不會大于1,我們可以將程序設計為:當等式兩邊的差值大于或等于1時,R每次遞增1;當等式兩邊的差值小于1時,R每次遞增0.01,這樣可以有效地提高運算的效率,并且使最終計算出的結果誤差在0.01內.如果我們想提高計算的精確度,就可以把當差值小于1時,R每次遞增的值設置得更小,這樣可以按照我們的需要來設置算法.
該算法的程序如下:
$(function ( ) {
var $a = $("#input-a");
var $b = $("#input-b");
var $l = $("#input-l");
$("#getResult").on("click", function (? ? ? ) {
var l = parseFloat($l.val( )); //弧長
var a = parseFloat($a.val( )); //長
var b = parseFloat($b.val( )); //高
if (isNaN(l) || isNaN(a) || isNaN(b))
{ alert("只能輸入數字");
return; }
var r = 1; var d = null;//差值小于0.001
var count = 0; //計算次數
var c = Math.sqrt(a * a + b * b);
do { var nd = Math.abs(Math.sin(l / (2 * r)) * (2 * r) - c);
if (nd <= 1) { //差值小于1
r += 0.01;? }
else { r += 1;? }
count++;? ? d = nd;
if (count > 200000) { alert('無法計算出結果');
return;? ?}
} while (d > 0.001);
alert("r=" + r.toFixed(2));
return false;? })});
其程序架構過程如圖4所示,其運算過程如圖5所示.
如果所輸入的參數不合要求,出現如[l≤a2+b2]的情況,則計算結果會提示“無法計算出結果”.為了防止程序進入死循環,我們需要增加內容:在計算200000次后,仍然沒有找到滿足條件的解,則為無解.此方法還可以推廣到解答其它不易直接求解的方程中.
(作者單位:四川省內江市第一中學)