<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### 7.2.4 編程實例:模擬炮彈飛行 本節討論一個模擬炮彈飛行的程序的設計。我們采用三種設計方法,得到三個版本的程序。通過比較各個版本的差別,可以看出 OOP 與傳統的面向過程編程相比具有明顯優點。 算法設計 程序規格是輸入炮彈的發射角度、初速度和高度,輸出炮彈的射程。 雖然可以利用復雜的數學公式直接算出射程,但我們采用模擬炮彈飛行過程的方法來求射程。所謂模擬炮彈飛行過程,就是從炮彈射出炮口開始,計算炮彈在每一時刻的位置(水 平距離和高度),直至炮彈落地。注意,時間和炮彈飛行軌跡都是連續的量,由于計算機不能 處理連續的數值,所以需要將時間和炮彈飛行軌跡“離散化”,也就是將時間劃分成一系列離 散的時段,飛行軌跡也相應地劃分成一系列離散的點。 炮彈在每一時段所處的位置可以利用簡單的中學物理知識求得。將炮彈速度分解成水平 分量和垂直分量,則炮彈在水平方向的運動是勻速直線運動(忽略空氣阻力),在垂直方向的 運動是加速運動(因為重力的影響,炮彈先向上減速飛行,減到向上速度為 0 后改為自由落 體運動)。算法偽代碼如下: ``` 算法:模擬炮彈飛行。 輸入:角度 angle(度)、初速度 v(米/秒)、高度 h0(米)、時間間隔 t(秒) 輸出:射程(米) 計算初速度分量:先將 angle 換算成弧度單位的 theta,再計算 xv = v * cos(theta),yv = v * sin(theta) 初始位置:(xpos,ypos) = (0,h0) 當炮彈還未落地(即 ypos &gt;= 0.0): 更新炮彈在下一時段的位置(xpos,ypos)和垂直速度分量 yv 輸出 xpos ``` > ① Java 和 C++中使用的是“this”。 為了理解此算法,請參看示意圖 7.9。 ![](https://box.kancloud.cn/2016-02-22_56cafce446e7c.png) 圖 7.9 模擬炮彈飛行的有關數據 炮彈飛行過程中,水平位置的更新很簡單:按照勻速直線運動的規律,每個時段 t 內, 炮彈都飛行 xv * t 距離,因此炮彈在水平方向從 xpos 運動到了新位置 ``` xpos = xpos + xv * t ``` 炮彈垂直方向位置的變化稍微復雜點:由于重力的影響,炮彈向上速度每秒減少 9.8 米/ 秒,經過時段 t,向上速度變成了 ``` yv1 = yv - 9.8 * t ``` 而炮彈在時段 t 內垂直方向位移可以用這段時間的平均速度乘 t 來計算,因為時段 t 內的平均 速度為起點速度 yv 與終點速度 yv1 之和的一半,故時段 t 內的垂直方向位移為 ``` (yv + yv1) / 2.0 * t ``` 于是,經過時段 t 后,炮彈在垂直方向的新位置為 ``` ypos = ypos + (yv + yv1) / 2.0 * t ``` 最后要說明的是,模擬炮彈飛行的循環語句的條件 y&gt;=0 中之所以用等號,是為了使程 序在初始高度為 h0 = 0 的情況下也能進入循環進行模擬。一旦算出炮彈最新高度小于 0,則 終止循環。 下面是完整程序: 【程序 7.4】cball1.py ``` # -*- coding: cp936 -*- from math import pi,sin,cos def main(): angle = input("輸入發射角度(度): ") v = input("輸入初速度(米/秒): ") h0 = input("輸入初始高度(米): ") t = input("輸入時間間隔(秒): ") theta = (angle * pi) / 180.0 xv = v * cos(theta) yv = v * sin(theta) xpos = 0 ypos = h0 while ypos >= 0: xpos = xpos + t * xv yv1 = yv - t * 9.8 ypos = ypos + t * (yv + yv1) / 2.0 yv = yv1 print "射程: %0.1f 米." % (xpos) main() ``` 以下是程序 7.4 的一次執行結果: ``` 輸入發射角度(度): 56 輸入初速度(米/秒): 300 輸入初始高度(米): 2 輸入時間間隔(秒): 0.1 射程: 8522.1 米. ``` 用寫作文打比方的話,程序 7.4 采用的是流水帳式的、毫無章法結構的作文方法,它將所有數據和操作語句全都混在一起。程序雖然不長,卻使用了 10 個變量,要想理解這個程序就必須時刻記牢并跟蹤這 10 個數據的變化,這對人腦來說是個不小的負擔。 模塊化程序設計有助于改善程序的結構,增強程序的易理解性。我們利用模塊化來重新組織程序 7.3 中的語句,形成一些具有相對獨立性的模塊(函數)。下面就是炮彈模擬程序的 模塊化版本: 【程序 7.5】cball2.py ``` # -*- coding: cp936 -*- from math import pi,sin,cos def getInputs(): a = input("輸入發射角度(度): ") v = input("輸入初速度(米/秒): ") h = input("輸入初始高度(米): ") t = input("輸入時間間隔(秒): ") return a,v,h,t def getXY(v,angle): theta = (angle * pi) / 180.0 xv = v * cos(theta) yv = v * sin(theta) return xv,yv def update(t,xpos,ypos,xv,yv): xpos = xpos + t * xv yv1 = yv - t * 9.8 ypos = ypos + t * (yv + yv1) / 2.0 yv = yv1 return xpos,ypos,yv def main(): angle, v, h0, t = getInputs() xv, yv = getXY(v,angle) xpos = 0 ypos = h0 while ypos >= 0: xpos,ypos,yv = update(t,xpos,ypos,xv,yv) print "射程: %0.1f 米." % (xpos) ``` 與程序 7.4 相比,程序 7.5 的主程序 main 顯得非常簡潔、容易理解。main 中用到的變量 從 10 個減到 8 個,少掉的兩個變量是 theta 和 yv1。變量 theta 存儲的是以弧度為單位的發射 角度,它是為了符合 math 庫中三角函數的用法而臨時創建的中間數據,對程序來說既不是輸 入數據,又不是輸出數據,也不是貫穿算法始終的關鍵數據。因此,將 theta 隱藏在用到它的 函數 getXY 中,是符合它的“跑龍套”身份的做法。基于同樣的理由,yv1 也被隱藏在了函 數 update 中。 然而,盡管模塊化編程改善了程序的結構,使程序易讀易理解,但程序 7.5 的主程序仍 然比較復雜。為了描述炮彈的飛行狀態,需要 xpos、ypos、xv 和 yv 等 4 個數據,其中 xpos、 ypos 和 yv 是隨時間 t 而變的,需要時時更新,這就導致了主循環中的那個復雜、累贅的函數 調用: ``` xpos,ypos,yv = update(t,xpos,ypos,xv,yv) ``` 函數作為功能黑盒子,應該提供簡明易用的接口,而 update 函數的設計顯然不夠簡明易 用,它需要輸入 5 個參數,并輸出 3 個返回值。這就像一臺設計拙劣的電視機,從機殼內伸 出七八根電線,買回家后需要完成復雜的接線之后才能收看電視。請記住,如果函數接口過 于復雜,往往表明這個函數的設計需要改善。 最后,我們用 OOP 來編寫炮彈模擬程序。炮彈原本是現實世界中的一個對象,傳統編 程方法卻用 xpos、ypos、xv 和 yv 等四個分離的數據來描述它,這是典型的“只見樹木不見 森林”。假如有一個 Projectile 類來描述炮彈對象,有關炮彈的一切信息和行為都封裝在這個 類中,那么在主程序中要做的就是創建一個炮彈對象,然后由這個對象自己完成所有的計算 任務,代碼形如: ``` def main(): angle, vel, h0, time = getInputs() cball = Projectile(angle, vel, h0) while cball.getY() >= 0: cball.update(time) print "射程: %0.1f 米." % (cball.getX()) ``` 這段程序的含義是:首先輸入炮彈的初始數據 angle、v、h0 以及計算炮彈飛行位置的時間間 隔 t;然后利用這些初始值創建炮彈對象;接著進入主循環,不斷請求炮彈更新其位置,直 至炮彈落地。程序中只用到必不可少的 4 個初始數據,其他數據都隱藏在 Projectile 類當中, 這使得程序邏輯非常清晰、易理解。 當然,主程序之所以簡單,是因為復雜性都被隱藏在類當中了。下面來考慮 Projectile 類 的定義。前面主程序中實際上已經提出了對類的要求,即類中必須實現 update、getX 和 getY 方法。此外,還必須定義類的構造器。 構造器 \_\_init\_\_用于初始化新創建的對象,比如為對象的實例變量賦初值。炮彈對象的實 例變量顯然應該包括描述炮彈狀態的四個數據:xpos、ypos、xv 和 yv。初始化代碼如下: ``` def __init (self, angle, velocity, height): self.xpos = 0.0 self.ypos = height theta = pi * angle / 180.0 self.xv = velocity * cos(theta) self.yv = velocity * sin(theta) ``` 注意變量 theta 的用途是臨時性的,其值只在此處用到,別處不需要,因此沒有必要將 theta 也作為炮彈對象的實例變量,而應作為普通的局部變量。 方法 getX 和 getY 很簡單,分別返回實例變量 self.xpos 和 self.ypos 的當前值即可。 update 方法是最核心的方法,它的任務是更新炮彈在某個時間間隔后的狀態。只需傳遞 一個時間間隔參數 t 給 update 即可,這比程序 7.5 中的 update 簡單多了。代碼如下: ``` def update(self,time): self.xpos = self.xpos + time * self.xv yv1 = self.yv - time * 9.8 self.yp = self.yp + t * (self.yv + yv1)/2.0 self.yv = yv1 ``` 注意 yv1 也是一個普通的臨時變量,它的值在下一次循環中就是 yv 的值,因此程序中將其值保存到實例變量 self.yv 中。 至此,我們就完成了 Projectile 類的定義。再添加 getInputs 函數后,就得到完整的面向 對象版本的炮彈模擬程序。 【程序 7.6】cball3.py ``` from math import pi,sin,cos class Projectile: def __init__ (self,angle,velocity,height): self.xpos = 0.0 self.ypos = height theta = pi * angle / 180.0 self.xv = velocity * cos(theta) self.yv = velocity * sin(theta) def update(self, time): self.xpos = self.xpos + time * self.xv yv1 = self.yv - 9.8 * time self.ypos = self.ypos + time * (self.yv + yv1) / 2.0 self.yv = yv1 def getX(self): return self.xpos def getY(self): return self.ypos def getInputs(): a = input("輸入發射角度(度): ") v = input("輸入初速度(米/秒): ") h = input("輸入初始高度(米): ") t = input("輸入時間間隔(秒): ") return a,v,h,t def main(): angle,v,h0,t = getInputs() cball = Projectile(angle,v,h0) while cball.getY() >= 0: cball.update(t) print "射程: %0.1f 米." % (cball.getX()) ``` 本程序三種版本的設計思想變遷,可以用圖 7.10 來刻劃。 ![](https://box.kancloud.cn/2016-02-22_56cafce45c541.png) (a) 非模塊化過程 (b) 模塊化 (c)面向對象 圖 7.10 炮彈模擬程序不同設計方法的變遷
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看