塑膠免洗餐具充斥 台中議員辦桌質詢

摘錄自2019年11月22日自由時報台中報導

台中市議員鄭功進、施志昌、林祈烽、黃守達、林德宇昨天(21日)針對一次性餐具及塑膠濫用問題提出質詢,並在議場實境辦桌,用的全是塑膠杯碗、美耐皿餐具及紙容器塑膠膜,批評整桌「塑化劑」,鄭功進穿上廚師裝,拿出塑膠袋、紙碗裝盛的餐點質詢,指「從桌布開始就全是塑膠垃圾!」

鄭功進表示,全市登記餐飲業超過一萬家,每人每日生產一般廢棄物1.23公斤,坊間餐館使用一次性免洗餐具及塑膠製品非常頻繁,連每年市府舉辦的環保志工隊聚餐、里鄰長文康活動,也常選擇不甚環保的公路餐廳用餐,常常使用大量塑化劑殘留的餐具,加上熱湯及酒水,政府不應漠視。

鄭功進也說,環保局每年僅編列約三萬元訪視輔導費,像台中知名燒肉餐廳推出的優惠方案,竟是自備餐具飲料第二杯半價,恐怕一整年使用綠色環保優惠的不到十人。

鄭功進要求由陳子敬領軍的低碳辦公室,應主動結合相關局處強化生產履歷、無塑化劑、食安環境及獎勵推廣等輔導團,在山海市屯各選出標竿示範餐廳輔導轉型,並進行綠色採購、增加誘因,真正落實低碳城市。

環保局回應,為鼓勵民間業者成為環保餐館,每年舉辦綠色消費表揚大會,希望帶動更多業者加入,另也承諾將改善環保志工等市府活動的用餐品質,打造綠色友善環境。

【其他文章推薦】

※找工作! 想知道堆高機駕駛日薪是多少嗎? 哪裡有職缺?幫你快速媒合

※隨時健康喝好水,高品質飲水機推薦,優質安全有把關

新北市轉軸代工廠商詢價平台?

防爆隔熱紙規格資訊說明

中、越豬肉持續驗出非洲豬瘟病毒 東亞僅台日非疫區

摘錄自2019年11月21日聯合新聞網台北報導

農委會防檢局今天(21日)表示,目前東南亞國家僅日本及我國沒有,分析今年6月至10月從疫區違規攜帶豬肉類製品的開罰案件件數逐步下降,按班機啟航國家或地區排序,分別為中國、香港、澳門、越南及韓國,又以31歲至50歲最多。

防檢局在邊境查驗時,持續在來自中國及越南旅客帶來的含豬肉產製品,檢驗出非洲豬瘟病毒核酸陽性,顯示國際間非洲豬瘟疫情仍然嚴峻,對我國養豬產業造成極大危害風險。

防檢局再次呼籲,民眾返國時不要攜帶動植物產品入境,也不要網購國外肉品寄送台灣,違者將遭受重罰,國內畜牧業者亦應加強生物安全措施,共同防堵非洲豬瘟入侵,保障養豬產業生產安全。

【其他文章推薦】

※有廠商專門客製化橡膠製品嗎?

噴霧洗滌塔實際應用案例分享

※票選推薦煮婦最愛手壓封口機,省荷包不犧牲品質

※選購空壓機需注意八大事項 !

※DIY自行施工建築隔熱紙,簡易教學大公開 !

外埔綠能園區 至今未發1度電

摘錄自2019年11月21日中國時報台中報導

台中市政府以ROT案興建外埔綠能生態園區推動廚餘發電,2019年7月起陸續推動生廚餘回收作業,至今未發出1度電;20日引起市議員陳清龍等人強烈質疑,是否有圖利廠商之嫌!

環保局表示,因附屬設施未營運已開罰4次,後續將依約持續辦理。 市議員陳清龍說,契約書中對「生廚餘」隻字未提,但實際作業上僅能收生廚餘,一般與事業廢棄物處理依舊無處可去。依契約書自營運第一年起市府至少交付1萬2000公噸廚餘;第二年至少交付2萬4000公噸,市府還須清運處理完的雜質及生活垃圾。

市議員陳政顯說,廠商應於2018年8月31營運,實際上厭氧設備於2019年7月才開始營運,電業許可發電尚未取得,荒腔走板,廠商已被開罰3次;營運期間績效不及格者視為違約,營運績效評估連續3年不及格者,應依重大違約規定辦理。

環保局強調,若ROT廠商經營不善,市府可依契約內所訂缺失及違約責任辦理;亦可啟動協商協調、賠償、仲裁、訴訟、強制接管等措施。

【其他文章推薦】

示波器鮮為人知的使用技巧?

※各大百貨每波促銷贈品活動,限量知名LOGOL型資料夾,獨家販售中!!

飲水機皆有含淨水功能嗎?

※選購空壓機需注意八大事項 !

真空封口機該不該買?使用心得分享

大樓隔熱紙施工分享說明,教你如何善用空間裝潢、設計 !

眼睛模糊、視力不好?老中醫教你一招恢複視力

我們都知道,眼睛是心靈的視窗,現在隨著手機和電視電腦的普及,我們會發現,低頭族越來越多。不只是在休息時間,在吃飯的飯桌上,甚至是在大街上走路,都有很多低頭看手機的情況。長久下來,視力下降的問題也越來越嚴重。今天就教給大家一個方便易操作的方法,對於緩解近視眼、老花眼有很大幫助,甚至對白內障也有一定治療作用。  

這個方法是首屆國醫大師、原首都醫科大學附屬北京中醫醫院針灸中心教授、在針灸界有「神針」之稱的賀普仁教授的經驗。一起來看看 
 

 賀普仁(1926年5月-2015年8月),首屆國醫大師,素有「神針」之稱。 
賀普仁在30多年前曾經得過白內障,眼睛差點失明了。
在當時的條件下,白內障沒有什麼特效的治療方法,只能手術。賀老不想挨這一刀,他開始用中醫方法調理自己的眼睛,視力竟然變好了! 

看書、讀報、打麻將都不用戴眼鏡,什麼都不耽誤!在晚年出診時,紮起針來依然又穩又准。85歲時,曾在中央電視台的節目中表演穿針引線,令人吃驚! 
如今玩手機的朋友比較多,眼睛用得也比以前多。看不清、視力模糊的情況真的不少,賀老的這個方法適用於所有朋友,還不花一分錢! 


一、轉睛功:通眼睛血脈、預防白內障 

方法很簡單,就是雙目微閉,全身放鬆,轉眼球,先順時針轉36次,再逆時針轉36次。 
   

▲ 賀普仁教授親自指導) 
這樣長期堅持鍛煉,對很多眼病都有療效,不僅僅是白內障,老花眼、近視眼都有治療和預防的作用。 
「這種功法使局部的經絡通暢,氣血運行加快,有些廢物隨時隨地就吸收了,這樣白內障就形成不起來。」賀普仁說。 

轉睛是自古以來就有的養眼方法,古人認為這樣可以疏通眼睛中的絡脈,化除「瘀滯」。 
現代醫學也發現,轉睛可以促進眼睛內部微血管擴張和血液循環,從而改善晶狀體的新陳代謝,促進病變和滲出物的吸收,有助於早中期白內障的控制。 

二、按承泣穴:防老花眼 
用食指按住承泣穴(目視正前方,黑眼球正下方,眼眶骨上的這個點),反覆揉搓。 

 

▲ 賀普仁教授親自指導)
早在47歲那一年,賀普仁眼睛就發花,視力減退,配過150度的老花鏡來看書。為了中止老花眼,賀普仁每天醒來第一件事,就是按揉承泣穴,這對眼睛供血有幫助。 

賀普仁另外三個養生法 

1、防感冒:按迎香穴 
迎香穴在鼻翼旁開約一釐米皺紋中(在鼻翼外緣中點旁,當鼻唇溝中),時常按摩,除了能讓鼻子呼吸通暢,還有兩個額外的功效:預防感冒和緩解牙疼。尤其是上齒牙痛時,用手指壓該穴,可以快速止痛。 

2、防耳病:按耳門、聽宮、聽會穴 
聽宮穴在面部,耳屏前張口時呈現陷下處。 
聽會穴在聽宮穴下方,與耳屏下方相對處。 
常按摩這三個穴位都能夠舒筋活血,使得聽力增強,同時,還能治療耳鳴、中耳炎等耳部疾病。 

3、健齒:叩齒36次 

每天早晨起床時,叩齒36次,能使牙齒堅固。
希望大家都能告訴身邊的朋友們,保護自己的眼睛一定要用有效的方法!最重要的是,放下手機讓眼睛休息一會兒!

本站聲明:網站內容來源http://www.look543.com,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

聽過「電子菸」嗎?想知道與一般傳統香菸有何不同嗎?

電子煙能幫助戒菸嗎?專家學者以健康觀點帶您來了解 !

新手該如何選擇電子菸口味及濃度呢?

原來「煮熟蘋果」竟然有很多好處「降糖降脂」以後再也不生吃蘋果了


  不論什麼季節我們都能吃到蘋果,但我們大多數都是生著吃的。

其實蘋果煮著吃好處挺多的! 

 

 腸道會變好

蘋果加熱以後,其中的膳食纖維果膠得以軟化,軟化後的膳食纖維和果膠更容易被人體利用。

而蘋果中的果膠有助於助排便,可以刺激腸內益生菌群的生長,同時也可以消炎等,同時可以治療腹瀉。
 
能夠降血糖降血脂

蘋果煮熟了以後再吃,可以起到很好的降血糖的作用,同時也可以降血脂,還可以很好地去抑制自由基的作用, 

從而可以起到很好的抗氧化的作用,同時也可以抗炎殺菌,可以很好地抑制血漿膽固醇升高。 
  

可以防治內熱

吃煮熟蘋果可防治嘴唇生熱瘡、牙齦發炎、舌裂等內熱現象。

其方法是:將蘋果連皮切成六至八瓣,放入冷水鍋內煮,待水開後,將蘋果取出,連皮吃下。

每天一次,每次一個,連吃7~10個可愈。此法還有潤腸通便的功效。經患者多次實驗,見效很快。
 

還能治療腹瀉

蘋果中富含的果膠,是一種能夠溶於水的膳食纖維,不能被人體消化。

果膠能在腸內吸附水分,使糞便變得柔軟而容易排出。

其實果膠還具有降低血漿膽固醇水平、刺激腸內益生菌群的生長、消炎和刺激免疫的機能。 
  

降低膽固醇

蘋果可以跟豬肉一起搭配煮著吃呢?

這樣既增加營養又可抑制膽固醇升高,因為蘋果中的膳食纖維有降低膽固醇的作用。而且蘋果可消除豬肉的獨特異味。 

另外,煮蘋果更適合一些特殊人群,臥病在床、口腔牙齒不健全或胃腸功能不好的人,可以減少咀嚼,減少對胃腸道的刺激,使得攝入更順暢。 
  

什麼時候吃蘋果最好?

蘋果酸甜可口,營養比較的豐富,很多的人喜歡吃蘋果,隨著生活節奏的加快,一般人都習慣晚上吃蘋果,

但是聽說早上吃蘋果最好,究竟蘋果什麼時候吃最好呢? 

專家提醒,蘋果早上吃最好,中午其次,晚上吃蘋果,其營養價值最低。

蘋果什麼時間吃最好?上去是金,中午是銀、下午是銅。

早上吃蘋果最好,因蘋果含有大量糖類,早晨人一般都處飢餓狀態下,蘋果可補充糖類,上午是人脾胃最旺盛的時候,吃蘋果很容易被身體吸收, 

所以早晨吃蘋果營養價值更高,蘋果空腹吃還可以助消化,具有提神效果比咖啡更有效。

早上吃的食物能吸收50%,而晚上吸收只有10%。 

蘋果什麼時間吃好,飯前還是飯後

一般飯前吃,因為蘋果裡的蘋果酸對消化有促進作用。

可選午餐、晚餐的一個小時之前,或者是兩餐之間,因水果的養分大多是水溶性的,容易被吸收, 

所以吃下去的水果養分,到了腸胃很快會被消化吸收。

飯前吃水果還有一個好處,可以減肥,因為相同份量的水果比起其他食物熱量較低, 

所以飯前吃水果能讓胃部有飽足感,這樣相對就會減少其他食物的熱量攝取,對於想要瘦身的人很有幫助。

本站聲明:網站內容來源http://www.look543.com,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

※聽過「電子菸」嗎?想知道與一般傳統香菸有何不同嗎?

電子煙能幫助戒菸嗎?專家學者以健康觀點帶您來了解 !

※新手該如何選擇電子菸口味及濃度呢?

你知道為什麼電影院要賣爆米花嗎?原來背後這麼有學問!

電影院是人們,
放假休閒的好去處,但你有沒有想過,
為何不管是哪間影廳,
都一定會販售”爆米花”,
想必這個問題,也是不少人的疑惑吧!
讓我們來一探究竟吧!

應該會有不少人回答:
「應該是他的毛利很高的緣故吧!」
靠著爆米花賺錢,比賺電影票還容易多了。

我覺得這種商業選擇,
類似於生物進化的自然選擇。

很可能在早期的電影院,
賣的食品種類非常復雜。
但是由於商業選擇,就只剩下很少的幾種,
而爆米花就是其中的王者。

其後的電影院就那麼沿襲了下來。
我不知道最早印第安人培育玉米的時候,
腦子裡有沒有出現過電影院這個概念,
但爆米花的確是電影院的絕配。

由於電影院的環境特殊,所以影院食品要符合一些特徵。

1、看電影的人,不會比電影開演時間早很多來影院。

人們來到電影院,
主要一定是要看電影呀!
但一般人不會在電影播放前,
提早太多前來。

但影院要對食物加工的時間,
就非常有限了,要在最短時間拿給客人,
並且拿到手裡還是熱呼呼的。

2、在黑暗的放映時間裡,影院食品要拿取方便。

在電影院裡,都是黑漆漆的空間,
如果食品是湯湯水水的,
萬一不慎翻倒了,不僅清潔不方便,
也造成了服務人員的麻煩,
所以食品最好是「乾」,
而爆米花就是很好的選擇!

3、影院食品最好不要過於油膩,不要有比較強的飽腹感,也最好不要有太強的味覺記憶。

這三個要求,
是為了保障人們不會因為吃的油膩,
而對電影產生厭惡感——
從行為學的角度講,你去相親,
如果你喜歡那個女孩,你最好不要請她第一次吃飯,
就吃麻辣火鍋之類的晚餐——

另外,人們一般娛樂習慣是,
先看電影再進行晚餐。
如果影院賣的東西太有飽腹感,
那麼人們會選擇在看電影時不吃東西。
這一個限制基本可以過濾掉蛋白質類食品,
和高密度澱粉類食品。

4、如果你還記得第一次電影院約會。
在進入放映廳前,
你總想讓這次活動再具有一些張力,
那麼給那個女孩,買一大盒爆米花是個很不錯的選擇。

高頻率吃爆米花,
既可以緩解尷尬和緊張又不會發胖。
另外,爆米花成本很低,影院可以在這上邊賺不少,
但總價又不會讓約會者感到難以承受。

爆米花還有個優勢,看起來很巨大,
這對於購買者來說很滿足。

對於影院來說,他們不希望觀眾外帶食品,
當然也不歡迎看電影的人自帶爆米花,
爆米花的巨大效益,給更經濟的約會者帶來了一定困難。

本站聲明:網站內容來源http://www.look543.com,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

※聽過「電子菸」嗎?想知道與一般傳統香菸有何不同嗎?

電子煙能幫助戒菸嗎?專家學者以健康觀點帶您來了解 !

※新手該如何選擇電子菸口味及濃度呢?

人走後要用布蓋臉?是有科學根據的,古人的智慧呀

自古以來,人們都知道,如果人走了之後,會需要一些麻煩又複雜的儀式。
以前,這些儀式算是幫助死者,也算是對死者的一種尊重。
當然啦!人生當中最重要的就是兩件大事,一是生,二是死。

所以我們看孩子出生時,還是生日或節日,我們都會用各種方式來祝賀。

例如過百也會,所以理所當然的,人死後的儀式也更加的複雜了。

就我有印象以來,當時還小,身邊的老人家過世時,都得要舉辦特別的、每次都不同的儀式。

來說說那個送殯的過程吧:

儀式一定要走一段路,就設一個靈棚!

而且家族中所有的人必須要虔誠的跪拜,直到將老人送出去才能夠起來,接著送去火化。

雖然,在現代這個社會上,儀式簡化了相當多了。

可是有部分的人難免會有不想法,因為儀式的簡化的關係,有人覺得簡化了儀式代表著文明進步,可是有人覺得簡化後,是直接地承認而且拋棄了傳統的文化禮儀。

總之無論如何解釋似乎都說的過去,如果大家留心的話,會發現在老人去世的時候,家裏人一般要在逝者的臉上蒙上一張紙,這是為什麽呢?

其實這其中大有講究,人沒了呼吸並不一定是真正死亡,還有一種假死的可能,假死就是人暫時昏迷,而假死經過及時搶救是完全可以搶救過來的。

所以為了避免因假死而造成不必要的悲劇,因此古人發明了很多辦法來區別真死和假死,比如古代要停靈七天,大戶人家要做四十九天的法事,實際上都是為了鑒別人是否真正死亡。

如果是假死,停靈七天可能就會救回一條人命。

如果人當天死亡就去埋葬,可能會出現意外。

同樣,在死者臉上放一張紙也是這個作用,人一旦還有呼吸便會把紙吹落。

這也是鑒別人是否真正死亡的一種方法。

當然還有一種說法是人死後臉上蒙紙是為了避免嚇到親屬,因為死者面目猙獰,非常難看,難免會讓人有一種畏懼的心理,所以才將死者的臉蒙上。

最後還有一種說法是這其實是古代流傳下來的一種習俗,那麽這種習俗起源於什麽時候呢?

大家都知道臥薪嘗膽這個故事,講的是當年越國被吳國打敗,越王勾踐為了保存國家甘願到吳國為奴,在吳國受盡了屈辱,勾踐表面對吳王恭恭敬敬,但是內心卻深以為恥,為了讓自己不忘今天的屈辱,勾踐在自己的臥室內放了一顆豬苦膽,每次睡覺前都要舔一舔,後來吳王以為自己已經徹底征服了勾踐,因此便對勾踐心存仁慈。

而伍子胥一直勸諫吳王一定要殺掉勾踐,可惜吳王不聽,後來把伍子胥急得不行,幹脆以死相逼,並告訴吳王把他的頭掛在城門上,他要親自看著越國打進吳國的國都,結果後來果真應驗,吳王走投無路自殺身亡。

所以歷史記載最早的死後覆面的人,就是春秋時期吳王夫差,他在被越往勾踐滅國之後,死之前對手下的人說,我死了之後,請用白布蓋住我的臉,因為我實在是死後到了陰曹地府不敢面對伍子胥。

大明崇禎皇帝在死前也寫下:
朕死,無面目見祖宗於地下,自去冠冕,以發覆面。
任賊分裂朕屍,勿傷百姓一人。


可見死後用東西蓋住臉是自古就有的,那麼這麼做只是一種習俗嗎?
還是有著科學的依據呢?

答案是肯定的,而且從裡面不難體會古人的智慧,下面我們就看看死後用東西覆面的科學之處。

1、從現代醫學的角度來看,人死之後,人體寄生的病菌失去了寄主,會離開死去的宿主,蓋住臉,能防止腸胃中的病菌飛出。

2、人死之後,用紙蓋住臉,因為紙較輕,如果人還沒有死,只是暫時的沒有呼吸,那麼呼吸的氣體會引發紙的晃動,避免人沒死就被埋了的結果。

3、古人有停屍三天的習慣,人死之後臉色肯定不太好看,這樣能避免引起前來弔喪人的恐懼。
4、遮住塵土,為了防止塵土落到死者的臉上,給死者一片乾淨,也是對死者的一種尊重。

難怪啊,只記得是這樣做,可是卻從不知道是為什麼!
 

本站聲明:網站內容來源http://www.look543.com,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

※聽過「電子菸」嗎?想知道與一般傳統香菸有何不同嗎?

電子煙能幫助戒菸嗎?專家學者以健康觀點帶您來了解 !

※新手該如何選擇電子菸口味及濃度呢?

熬夜常常熊貓眼?吃什麼食物可以消黑眼圈?綠茶可以輕鬆去除

黑眼圈比皺紋以及銀髮更能讓人顯老,常常讓人感到非常困擾!

不過,不用擔心,黑眼圈是可以淡化甚至完全消除的,如果你想知道怎麼做,那麼一定不要錯過,今天為大家介紹八種食物,能去除讓人煩惱的黑眼圈~~~~

1.芹菜

常吃芹菜,尤其是吃芹菜葉,對預防高血壓、動脈硬化等都十分有益,並有輔助治療作用

芹菜可炒,可拌,可熬,可煲,還可做成飲品,芹菜是女人美容食物,可以調節內分泌,促進血液循環,同時能補充纖維和蛋白,對淡化黑眼圈有顯著療效

2.柑橘

柑橘中所含有的抗氧化元素,諸如維生素C、葉酸、食物纖維素、其它維生素及礦物質對健康都非常有益

柑橘和綠茶的黃金組合具有防輻射的作用,同時,柑橘還可以補充人體所必須的纖維元素,促進內吸收,平衡人體各項元素,常食柑橘能夠美白,去皺,同時對黑眼圈有妙用

3.紅棗

大棗、小棗除用來製作各種美食外,還具有養血安神和養顏潤面之功效,是極佳的營養保健食品

其食用方法分生食,調粥,煲湯,飲料和美食。女人多吃紅棗可以養氣養血,增加面部光澤,減少因貧血引起的黑眼圈,同時可以促進吸收,補充鐵等微量元素

4.檸檬水

早上多喝檸檬水,可以有效的促進血液循環,引導有害物質排出,減低在體內的積聚機會,也可以減少黑眼圈,每天最好能夠達到一定的飲水量,同時,檸檬也有排毒美白的功效

5.芝麻

芝麻烏髮的作用人盡皆知,但其消除黑眼圈的功效可能就鮮人知曉了,芝麻富含對眼球和眼肌具有滋養作用的維生素E,從而能緩解黑眼圈的形成

既能使秀髮烏黑靚麗,又能消除黑眼圈,一舉兩得,難怪有人將芝麻視為神奇「魔法食物」,除了芝麻,富含維生素e的其他食物還有花生、核桃、葵花子等

6.胡蘿蔔

除了維生素E能對眼球和眼肌有滋養作用外,維生素a也有此般功效,胡蘿蔔就是增加維生素a攝入量的不二選擇,它能維持上皮組織正常機能,改善黑眼圈

此外,胡蘿蔔中所含的維生素a還有助於增進視力,尤其是黑暗中的視力,其他蘊含維生素a的食物還有苜蓿、杏等

7.海帶

由於鐵質是構成血紅蛋白的核心成分,因此,補充適量的鐵質能夠促使血紅蛋白的增加,從而增強其輸送氧分和營養成分的能力,而海帶富含鐵質,所以經常服用海帶,也能緩解黑眼圈的困擾

8.綠茶

經常使用電腦者可飲用綠茶,補充特異性植物營養素,消除因電腦輻射引起的黑眼圈

綠茶所含有的濃縮多酚,能抑制自由基對皮膚支持纖維造成破壞,是今日一致公認最有效的抗自由基因子,多喝低咖啡因的綠茶不僅能消除黑眼圈

其含有的兒茶素,既能幫助身體脂肪代謝,而且對睡眠也有幫助,不僅可以安定睡眠質量,也讓人比較不容易有疲勞感覺

多吃這些對身體有益幫助的食物,相信你也能輕鬆對抗惱人的黑眼圈!
 

本站聲明:網站內容來源http://www.look543.com,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

※聽過「電子菸」嗎?想知道與一般傳統香菸有何不同嗎?

電子煙能幫助戒菸嗎?專家學者以健康觀點帶您來了解 !

※新手該如何選擇電子菸口味及濃度呢?

[ch02-02] 非線性反向傳播

系列博客,原文在筆者所維護的github上:,
點擊star加星不要吝嗇,星越多筆者越努力。

2.2 非線性反向傳播

2.2.1 提出問題

在上面的線性例子中,我們可以發現,誤差一次性地傳遞給了初始值w和b,即,只經過一步,直接修改w和b的值,就能做到誤差校正。因為從它的計算圖看,無論中間計算過程有多麼複雜,它都是線性的,所以可以一次傳到底。缺點是這種線性的組合最多只能解決線性問題,不能解決更複雜的問題。這個我們在神經網絡基本原理中已經闡述過了,需要有激活函數連接兩個線性單元。

下面我們看一個非線性的例子,如圖2-8所示。

圖2-8 非線性的反向傳播

其中\(1<x<=10,0<y<2.15\)。假設有5個人分別代表x、a、b、c、y:

正向過程

  1. 第1個人,輸入層,隨機輸入第一個x值,x取值範圍(1,10],假設第一個數是2
  2. 第2個人,第一層網絡計算,接收第1個人傳入x的值,計算:\(a=x^2\)
  3. 第3個人,第二層網絡計算,接收第2個人傳入a的值,計算b:\(b=\ln (a)\)
  4. 第4個人,第三層網絡計算,接收第3個人傳入b的值,計算c:\(c=\sqrt{b}\)
  5. 第5個人,輸出層,接收第4個人傳入c的值

反向過程

  1. 第5個人,計算y與c的差值:\(\Delta c = c – y\),傳回給第4個人
  2. 第4個人,接收第5個人傳回\(\Delta c,計算\Delta b:\Delta b = \Delta c \cdot 2\sqrt{b}\)
  3. 第3個人,接收第4個人傳回\(\Delta b,計算\Delta a:\Delta a = \Delta b \cdot a\)
  4. 第2個人,接收第3個人傳回\(\Delta a,計算\Delta x:\Delta x = \Delta a / 2x\)
  5. 第1個人,接收第2個人傳回\(\Delta x,更新x:x = x – \Delta x\),回到第1步

提出問題:假設我們想最後得到c=2.13的值,x應該是多少?(誤差小於0.001即可)

2.2.2 數學解析解

\[c=\sqrt{b}=\sqrt{\ln(a)}=\sqrt{\ln(x^2)}=2.13\]
\[x = 9.6653\]

2.2.3 梯度迭代解

\[ \frac{da}{dx}=\frac{d(x^2)}{dx}=2x=\frac{\Delta a}{\Delta x} \tag{1} \]
\[ \frac{db}{da} =\frac{d(\ln{a})}{da} =\frac{1}{a} = \frac{\Delta b}{\Delta a} \tag{2} \]
\[ \frac{dc}{db}=\frac{d(\sqrt{b})}{db}=\frac{1}{2\sqrt{b}}=\frac{\Delta c}{\Delta b} \tag{3} \]
因此得到如下一組公式,可以把最後一層\(\Delta c\)的誤差一直反向傳播給最前面的\(\Delta x\),從而更新x值:
\[ \Delta c = c – y \tag{4} \]
\[ \Delta b = \Delta c \cdot 2\sqrt{b} \tag{根據式3} \]
\[ \Delta a = \Delta b \cdot a \tag{根據式2} \]
\[ \Delta x = \Delta a / 2x \tag{根據式1} \]

我們給定初始值\(x=2,\Delta x=0\),依次計算結果如表2-2。

表2-2 正向與反向的迭代計算

方向 公式 迭代1 迭代2 迭代3 迭代4 迭代5
正向 \(x=x-\Delta x\) 2 4.243 7.344 9.295 9.665
正向 \(a=x^2\) 4 18.005 53.934 86.404 93.233
正向 \(b=\ln(a)\) 1.386 2.891 3.988 4.459 4.535
正向 \(c=\sqrt{b}\) 1.177 1.700 1.997 2.112 2.129
標籤值y 2.13 2.13 2.13 2.13 2.13
反向 \(\Delta c = c – y\) -0.953 -0.430 -0.133 -0.018
反向 \(\Delta b = \Delta c \cdot 2\sqrt{b}\) -2.243 -1.462 -0.531 -0.078
反向 \(\Delta a = \Delta b \cdot a\) -8.973 -26.317 -28.662 -6.698
反向 \(\Delta x = \Delta a / 2x\) -2.243 -3.101 -1.951 -0.360

表2-2,先看“迭代-1”列,從上到下是一個完整的正向+反向的過程,最後一行是-2.243,回到“迭代-2”列的第一行,2-(-2.243)=4.243,然後繼續向下。到第5輪時,正向計算得到的c=2.129,非常接近2.13了,迭代結束。

運行示例代碼的話,可以得到如下結果:

how to play: 1) input x, 2) calculate c, 3) input target number but not faraway from c
input x as initial number(1.2,10), you can try 1.3:
2
c=1.177410
input y as target number(0.5,2), you can try 1.8:
2.13
forward...
x=2.000000,a=4.000000,b=1.386294,c=1.177410
backward...
delta_c=-0.952590, delta_b=-2.243178, delta_a=-8.972712, delta_x=-2.243178
......
forward...
x=9.655706,a=93.232666,b=4.535098,c=2.129577
backward...
done!

為節省篇幅只列出了第一步和最後一步(第5步)的結果,第一步時c=1.177410,最後一步時c=2.129577,停止迭代。

代碼位置

ch02, Level2

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

平板收購,iphone手機收購,二手筆電回收,二手iphone收購-全台皆可收購

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

PL真有意思(四):控制流

前言

對大多數計算模型而言,順序都是基本的東西,它確定了為完成所期望的某種工作,什麼事情應該最先做,什麼事應該隨後做,我們可以將語言規定順序的機制分為幾個類別:

  • 順序執行
  • 選擇
  • 迭代
  • 過程抽象
  • 遞歸
  • 併發
  • 異常處理和推斷
  • 非確定性

對於不同類別的語言對不同類別的控制流的重要性也不盡相同,比如順序執行相比於函數式對於命令式則更加重要。而命令式中更傾向用迭代,函數則更強調遞歸

表達式求值

在討論控制流之前先討論下錶達式的問題,先明確兩個概念:運算符通常是指那些採用特殊語法形式的內部函數(比如+-*/等),運算對象指的是運算符的參數(如2+3,2和3就是運算對象),那麼運算符和運算對象的組合就是表達式。一般根據運算符出現的位置(相對於運算對象而言),可以分為3類表示形式:前綴、中綴和後綴。比如Lisp就運用前綴語法:

(+ 1 3 4 6)      
(* (+ 1 7) 8)    

大多數命令式語言對二元運算符都使用中綴記法,而對一元運算符和其它函數使用前綴激發。但是像Lisp就全部統一使用中綴記法

優先級和結合性

大多數程序設計語言都提供豐富的內部算術。在用中綴方式(沒有括號)寫出就可能出現歧義。所以就需要優先級和結合性來解決歧義性,但是我覺得

媽的你寫括號就完事兒了

而且不同語言的優先級和結合性也不盡相同

賦值

在純函數式語言中,程序的基本組成部分是表達式,計算也僅是對表達式求值。任何一個表達式對於整個計算的影響也僅限於這個表達式所處的上下文環境。

而命令式語言的情況與此截然不同,計算通常是通過對內存中變量值的一系列修改操作來完成,賦值就是這種修改的最基本手段。每一次賦值都表示一個值被放入一個對應的變量中。

一般來說,如果語言中的一個結構除了返回一個值供其外圍環境所使用,還能以其他方式影響後續計算(並最終影響程序輸出),那麼我們就說這種結構有副作用。而副作用也是命令式語言里最核心的部分

而在純函數語言中沒有任何的副作用,表達式的值只依賴於輸入

但是現在許多語言都是混合的,像Python和Ruby主要是命令式的,但是也提供了很多的函數式的特徵,現在連Java都提供了對函數式的支持

引用和值

考慮一下下面的C語言的賦值:

d = a;
a = b + c;

第一個語句中,賦值語句右部引用了a的值,並希望把這個值放入d。第二個語句左部引用了a的位置,希望把b+c的結果放進去。這兩種解釋(值和位置)都是可行的,因為c語言中變量就是能保存值的命名容器,所以我們會說類似的語言的變量是值模型。由於指示位置的表達式被放在賦值語句的左部,所以這種指示位置的表達式成為左值表達式。表示一個值的表達式稱為右值。在變量的值模型下,同一表達式也可能是左值或者右值,比如(a=a+1),左部的a是左值,用於表示存放結果的位置;右部的a是右值,用於代表a具體所指的值。

在採用了變量的引用模型的語言中,這種左值和右值的差異就更加明顯了。

b = 2;
c = b;
a = b + c;

在值模型語言中程序員會說:“把2放入b,然後複製到c,然後用它們兩個的值相加,把結果4放入a。”。;

在引用模型語言中的程序員會說:“讓b引用2,讓c也引用2,然後把這兩個引用送給+運算,並讓a引用算出的結果,也是4“。

而在Java中,對於內部類型使用值模型,而類使用引用模型

裝箱

對於內部類型使用值模型,就無法以統一的方式將它們傳給要求類類型的參數的方法,所以這裏就需要一個裝箱過程

比如Java提供的Integer類

Integer i = new Integer(12);

多路賦值

我們知道賦值操作有右結合性,這使得我們可以寫出a=b=c的簡練代碼,在一些語言中(Ruby,Go,Python)我們可以進一步這樣寫:

a, b = 1, 2;
//上面的語句結果就是a等於1,b等於2。

a, b = b, a;
//交換兩個值,如果沒有這種語言特性,那麼就需要引入臨時變量了。

a, b , c = funx(d, e, f);

這種記法也消除了大多數程序設計語言中函數的非對稱性,這些語言可以允許任意多個參數,但只能返回一個返回值。但是其實在Python中的返回多個值,就是將多個值封裝為元組,在賦值的時候又拆箱而已

初始化

並不是所有語言都提供聲明變量時指定初始值的方式,但是至少有這幾點可以證明提供初始值的機制是有益的

  • 局部靜態變量需要一個初始值才能使用
  • 使用靜態分配的變量,可以由編譯器放入全局內存,避免了在運行時賦予吃數值所造成的開銷
  • 可以避免意外的使用未初始的變量

如果聲明時沒有明確的給定變量的初始值,語言也可以給定一個默認值。像C、Java和C#也都提供了類似的機制

動態檢查

除了可以指定默認值之外,還可以採用另外一種方式,將對為初始化的變量的使用作為動態語義錯誤,在運行時捕獲這種錯誤。但是在運行時捕獲所有使用到未初始化的情況的代價非常高

定義性賦值

在Java和C#中提供了一種定義性賦值的表示形式,意思就是由編譯器來檢查在達到一個表達式的所有可能控制路徑上,都必須為這個表達式中的每個變量賦過值

構造函數

許多面向對象語言都提供了為用戶定義的類型的自動初始化方法,也就是構造函數

在C++中,還區分了初始化和賦值,它將初始化賦值解釋為調用變量所屬類型的構造函數,以初始值作為調用參數。在沒有強制的情況下,賦值被解釋為調用相關類型的賦值運算符,如果沒有定義賦值運算符,就默認將賦值右部的值簡單的按位複製過來

區分初始化和賦值的好處是,可以區分在賦值前是不是需要先釋放空間

表達式的順序問題

雖然優先級和結合性規則定義了表達式里二元中綴運算符的應用順序,但卻沒有明確說明特定運算符的各運算對象的求值順序。舉例來說,如下錶達式:

 a - f(b) - c * d

根據結合性可知a-f(b)將在第二個減法前執行,根據優先級可知第二個減法的右運算對象是cd這個整體而不是c。但是如果沒有進一步的規則描述,我們無法得知a-f(b)是否在cd之前運行。諸如此類:對於f(a,g(b),c)這個子程序調用,我們也不知這三個參數的求值順序。

求值順序之所以重要:

  • 副作用:如果f(b)這個子程序可能會修改c的值,那麼a-f(b)-cd的求值結果將依賴f(b)和cd哪一個先執行;類似的,如果g(b)修改了a或者c的值,那麼f(a,g(b),c)的結果也是依賴於參數的求值順序。

  • 代碼改進:子表達式的求值順序對於寄存器分配和指令調度都有重要的影響。比如(ab+f(c)),我們可能會希望在執行ab之前調用f(c)。因為如果先計算乘法,則在調用f(c)之前就要先保存起來乘積,因為f(c)可能會用光所有的寄存器。

短路求值

對於布爾表達式,如果編譯器可以對其執行短路求值,那麼它生成的代碼可以在表達式前一半的結果可以確定整個表達式的值的情況下跳過後一半的計算。

比如(a<b) and(b<c),如果a>b,那麼完全沒必要去檢查b是否小於c就可以確定這個表達式一定為假。在一些特殊情況下,短路求值可節省大量時間,比如if(func&&func())。實際上這種情況下短路求值已經改變了布爾表達式的語義,如果非短路求值,那麼在func不存在的情況下去執行func(),程序是會拋出錯誤的。

我們常見的語法表現形式是&&和||這種布爾運算符身兼多職,既是布爾運算符又會觸發短路求值,但是有一些語言針對短路求值是有單獨的語法形式的,比如Clu語言中布爾運算符是and和or,短路運算符是cand和cor。這是為何呢,因為有些代碼邏輯是不需要這種短路求值的優化的。

結構化和非結構化的流程

彙編語言中的控制流通過有條件的或無條件的跳轉(分支)指令來完成,早期的高級語言模仿這種方式(如Fortran),主要依賴goto來描述大部分非過程化控制流,比如下面代碼:

if A < B goto label1;

label1;

但是如今goto像在Java、Clu和Eiffel里已經完全被禁止了,在其它語言也是受限了或者只是為了向前兼容而已

goto的結構化替代品

對於goto被廢棄,各種使用goto的地方也被結構的方案給代替了

  • 循環中的退出和繼續

break和contiune這兩個關鍵字大家應該很熟悉了

  • 從子程序提前返回

return

  • 多層返回

上面的兩個問題都可以有很好的替代品,但是對於多層返回就會比較麻煩一點。return或”局部的goto“只能在子程序中返回,如果遇到多層嵌套的子程序,想從內層的子程序返回來結束外圍子程序的執行,那return和局部的goto就無能為力了。這種情況下,語言實現要保證能恰當的恢復棧上的子程序調用信息,這種修復工作稱為”回卷”,為完成此事,不僅必須釋放需要跳出的所有子程序的棧幀,還要執行一些信息管理工作,比如恢復寄存器內容。

Common Lisp提供了return-from語句來明確指定需要退出的詞法外圍函數或嵌套塊,還可以提供一個返回值:

Common Lisp和另外一個語言Ruby中還內置一個throw/catch語法來支持這種多層返回,注意這種結構並不是所謂的異常處理,而是一種多層返回的語法結構,直白點說是一種功能強大的變相”goto“,看下面代碼:

//定義一個方法
def search_file(filename,pattern)
   file=File.Open(filename)
   //遍歷文件每一行
   file.each{|line|
        //根據parrern匹配模式查找,如果匹配就返回到定義found標籤的位置
        throw :found,line if line=~/#{pattern}/
   }
end

//用catch定義一個found標籤
math=catch:found do
   serach_file("f1",key) 
   serach_file("f2",key)    //如果f2文件找到了則就會返回line至math
   serach_file("f3",key)
   ”not fount“              //找不到就執行到此處了
end

print match
  • 錯誤和異常

多層返回的概念假定了被調用方知道調用方期的是什麼,並且能返回一個適當的值。還存在一種情況,其中深層嵌套的子程序中發生了一些情況,導致無法繼續執行下去,而且因為沒有足夠的環境信息,甚至無法合適的結束自己的工作,這種情況下,唯一能做的就是”退回去“,一直回退到能夠恢復執行的地方,這種要求程序退回去的條件通常稱為叫做”異常“。常見的結構化的異常處理和多層返回有很大的相似性,兩者都需要從某一個內層上下文回退到外層的上下文。具體的差異則是多層返回是內層的上下文正常的完成計算然後根據需要返回正確的值,然後轉移到外層上下文,並不需要後續處理。而異常中的內層上下文已經是無法進行正常的計算,必須以一種非正常的退出一直回卷,然後觸發某個特殊的處理流程直到catch到它。

  • 繼續

如果進一步推廣上一小節中造成棧回卷的非局部goto概念,則可以定義一種稱為繼續(Continuations)的概念。從底層來看,一個繼續是由一個代碼地址與其關聯的一個引用環境組成的,如果跳轉到這個地址,就該恢復這個引用環境。從抽象層面看,它描述一個可能由此繼續下去的執行上下文。在Scheme和Ruby中,繼續是基本的一等公民,我們可以利用這種機制有效的擴充流程控制結構集合。

Scheme中支持繼續由一個通常稱為call-with-current-continuation的函數實現,有時簡稱”call/cc”。該函數有一個參數f,f也是一個函數;”call/cc”調用函數f,把一個記錄著當前程序計數器和引用環境的“繼續(暫時稱為是c)c”傳遞給f,這種”繼續c”由一個閉包來表示(通過參數傳遞的子程序的表示的閉包並無不同)。在將來任何時候,f都可以調用c,然後可以用c來重新建立其保存的上下文。一般的應用情況是我們把這個c賦值給一個變量,則可重複的調用它,甚至我們可以在f中返回它,即使f已經執行完畢,仍然可以調用c。

順序執行

選擇

現在大部分命令式語言中採用的選擇語句,都是從Algol 60引進過的 if…then…else 的某種演進變形:

if condition then statement
else if condition then statement
else if condition then statement
...
else statement

短路條件

雖然 if…then…else 語句的條件是一個布爾表達式,但是通常沒有必要求出這個表達式的值放入寄存器。大部分機器都提供了條件分支指令(如上面提到的IL指令brtrue.s),因為這個表達式求值的目的並不是為了值,而是為了跳轉到合適的位置。這種看法使得可以對短路求值的表達式生成高效的代碼(稱為跳轉碼)。跳轉碼不但可以用於選擇語句,也可用在“邏輯控制的循環”中。如下面代碼:

if((A>B)&&(C<D)||(E!=F)){
    then_clause
}
else{
    else_clause
}

在不使用短路求值的Pascal中,生成的代碼大致如下(它會計算每個表達式的結果並放入寄存器r1…,然後再決定跳轉):

     r1=A
     r2=B
     r1=r1>r2
     r2=C
     r3=D
     r2=r2>r3
     r1=r1&r2
     r2=E
     r3=F
     r2=r2!=r3
     r1=r1|r2
     if r1=0 goto L2
L1: then_clause
    goto L3
L2: else_clause
L3:

跳轉碼的情況於此不同,它不會把表達式的值存入寄存器,而是直接跳轉(只用到了r1和r2兩個寄存器,明顯也不會針對整個表達式進行求值,比上面的要高效一些):

     r1=A
     r2=B
     if r1<=r2 goto L4
     r1=C
     r2=D
     if r1>r2 goto L1
L4: r1=E
     r2=F
     if r1=r2 goto L2
L1: then_clause
    goto L3
L2: else_clause
L3:

case/switch語句

對於if else結構來說,如果嵌套的層數過多、或者是用於判斷的條件表達式是基於一些有限的簡單值(或編譯時常量),那麼出現了一種更為優雅的語法結構“case語句”,有很多ifelse都可以很輕鬆的改寫成case/switch語句

對於case/switch的優勢還不只是語法上的優雅,有時還可以生成更高效的代碼

T: &L1
   &L2
   &L3
   &L4
   &L5
   &L6
L1: clause_A
    goto L7
L2: clause_B
    goto L7
L3: clause_C
    goto L7
L4: clause_D
    goto L7
L5: clause_E
    goto L7
L6: clause_F
    goto L7
L7:

這樣其實T就是一個地址跳轉表

迭代

迭代和遞歸是計算機能夠重複執行一些操作的兩種機制;命令式語言傾向於使用迭代、函數式語言則更看重遞歸。大多數語言中的迭代都是以循環的形式出現的,和複合語句中的語句一樣,迭代的執行通常也是為了副作用,也就是修改一些變量的值。根據用何種方式控制迭代的次數來看,循環有兩個主要變種”枚舉控制的循環”和“邏輯控制的循環”。前者是在給定的某個有限的集合中執行,後者則是不確定要執行多少次(直到它所依賴的表達式結果被改變)。對於這兩種結構,大多數的語言都提供了不同的語法結構來表示。

枚舉控制的循環

枚舉控制的循環最初來自Fortran的do循環,

do i = 1, 10, 2
  ...
enddo

等號後面的表達式分別是i的初始值,邊界值和步長

像這種枚舉循環可以說的不多,但是如果前幾次迭代的執行會導致迭代的次數或下標值的發生變化,那麼我們就需要一個更通用的實現

思考幾個問題:

  • 控制是否可以通過枚舉之外的任何方式進入和離開循環呢?
  • 如果循環體修改了用於計算循環結束邊界的變量,會發生什麼?
  • 如果循環體修改了下標變量,會發生?
  • 程序是否可以在循環結束後讀取下標變量,如果可以,它的值將是什麼?
  1. 現在的大多數語言都提供了,break類似的機制來離開循環。Fortran IV允許通過goto跳入到一個循環中,但是這個通常被認為是一個語言缺陷
  2. 同樣的,在大多數語言中,邊界值只在第一次計算,並且保存在一個臨時寄存器中,所以對於之後的修改並不會起作用
  3. 早期的大部分語言都禁止在枚舉控制的循環中修改下邊變量。但是剛剛試驗了一下,許多的語言好像都放開了這個禁止,也就是按照修改后的正常邏輯繼續執行
  4. 首先這是一個語言實現的問題,現在的大多數語言應該都是將循環下標的作用域限定在循環體內了,所以出了循環體是訪問不到的

當然在之後出現了C的for循環

for (int i = first; i < last; i += step) {
  ...
}

這樣有關結束條件、溢出和循環方向的問題全都交由程序員來掌控

迭代器

上面描述的循環都是在算術值的序列上迭代。不過一般而言,我們還希望可以在任何定義的良好的集合的元素上迭代。在C++和Java里叫做迭代器

真迭代器

Clu,Ruby等語言允許任何容器對象提供一個枚舉自己元素的迭代器,這種迭代器就像是允許包含yield語句的子程序,每次yield生成一個循環下標

在Python里就可以這樣寫

for i in range(first, last, step):
    ...

在被調用時,這個迭代器算出循環的第一個下標值,然後通過yield語句返回給調用者,yield語句很像return,但是不同的是再每次循環結束后控制權會再次的交給迭代器,重新開始下一次yield,直到迭代器沒有元素可yield為止才結束for循環。從效果上看迭代器就像是另外一個控制線程,有它自己的程序計數器,它的執行與為它提供下標值的for循環交替執行,這一類通常稱為真迭代器。

迭代器

在許多面向對象語言里,用了更加面向對象的方法來實現迭代器。它們的迭代器就是一個常規對象,它提供了一套方法,用來初始化、生成下一個下標值和檢測結束條件

BinTree<Integer> myTree;

for (Integer i : myTreee) {

}

上面的這段代碼其實是下面這段的一個語法糖

for(Iterator<Integer> it = myTree.iterator();it.hasNext();) {

}

用一級函數來實現迭代器

實現是將循環的體寫成一個函數,用循環的下標作為函數的參數,然後將這函數作為參數傳遞給一個迭代器

(define uptoby
    (lambda (low high step f)
        (if (<= low higt)
            (begin
                (f low)
                (uptoby (+ low step) high step f))
            '())))

不用迭代器的迭代

在那些沒有真迭代器或者迭代器對象的語言中,還是可以通過編程方式實現集合枚舉和使用元素之間的解耦的,用C語言做例子:

tree_node *my_tree;    
tree_iter ti:                 
...
for(ti_create(my_tree,&ti);
              !ti_done(ti);
              ti_next(&ti)){
     tree_node *n=ti_val(ti);
     ...
}
ti_delete(&ti);

邏輯控制的循環

和枚舉循環相比,邏輯控制的循環關注點只在結束條件上

前置檢測

由Algol W引進,後來被Pascal保留

while cond do stat

後置檢測

這種的循環體不管是否滿足循環條件,都至少會執行一次循環體。如C語言的do while語句

do{
   line=read_line();
   //...代碼
} while line[0]!='$'; 

中置檢測

中置檢測一般依賴if

for(;;){
   line=read_line();
   if line[0]!='$' break;
}

遞歸

遞歸和上述討論的其他控制流都不同,它不依賴特殊的語法形式,只要語言允許函數直接或間接的調用自身,那麼就是支持遞歸的。大部分情況下遞歸和迭代都可以互相用對方重寫的。

迭代和遞歸

早期的一些語言不支持遞歸(比如Fortan77以前的版本),也有一些函數式語言不允許迭代,然而大部分現代語言都是同時支持兩者的。在命令式語言中,迭代在某種意義上顯得更自然一些,因為它們的核心就是反覆修改一些變量;對於函數式語言,遞歸更自然一些,因為它們並不修改變量。如果是要計算gcd(更相減損法),遞歸更自然一些:

int gcd(int a,int b){
  if(a==b) return a;
  else if (a>b) return gcd(a-b,b);
  else return gcd(a,b-a);
}

用迭代則是這樣:

int gcd(int a,int b){
   while(a!=b){
      if(a>b) a=a-b;
      else  b=b-a;
   }
   return a;
}

尾遞歸

經常有人說迭代比遞歸效率更高,其實更準確的說法應該是,迭代的樸素實現的(無優化)效率通常比遞歸的樸素實現的效率要高。如上面gcd的例子,如果遞歸的實現確實是實實在在的子程序調用,那麼這種子程序調用所帶來的棧的分配等的開銷確實要比迭代要大。然而一個“優化”的編譯器(通常是專門為函數式語言設計的編譯器),常常能對遞歸函數生成優異的代碼,如上面的gcd尾遞歸(尾遞歸函數是指在遞歸調用之後再無其他計算的函數,其返回值就是遞歸調用的返回值)。對這種函數完全不必要進行動態的棧分配,編譯器在做遞歸調用時可以重複使用當前的棧空間,從效果上看,好的編譯器可以把上面遞歸的gcd函數改造為:

int gcd(int a,int b){
start:
   if (a==b) return a;
   else if (a>b){
     a=a-b;
     goto start;  
   }
   else{
     b=b-a;
     goto start;
  }
}

即使是那些非尾遞歸函數,通過簡單的轉換也可能產生出尾遞歸代碼。

應用序和正則序求值

在上述的討論中,我們都假定所有參數在傳入子程序之前已經完成了求值,但是實際中這並不是必須的。完全可以採用另外一種方式,把為求值的之際參數傳遞給子程序,僅在需要某個值得時候再去求它。前一種在調用前求值的方案稱為應用序求值;后一種到用時方求值的方式稱為正則序求值。正則序求值在宏這個概念中是自然而然的方式,前面討論的短路求值、以及後面要討論的按名調用參數也是應用的正則序求值,一些函數式語言中偶爾也會出現這種方式。

但是我們來看一個例子:

#define MAX(a,b) ((a)>(b)?(a):(b))

如果我這麼調用MAX(i++,j++),導致i和j都執行兩次++,產生了兩次副作用,這是我們不願意看到的結果。總結來說,只有在表達式求值不會產生副作用的情況下正則序才是安全的。

惰性求值

從清晰性和高效的角度看,應用序求值通常會比正則序合適一些,一次大部分語言都採用如此的方式。然而也確實有一些特殊情況下正則序更高效一些,而應用序會造成一些錯誤出現,這種情況的出現時因為一些參數的值實際上並不會被需要,但是還是被求值了,應用序求值有時也成為非惰性求值,比如下面的JavaScript代碼就會是一個死循環:

function while1() {
    while (true) { console.log('死循環')}
}
function NullFunction() { }
console.log(NullFunction(1,2,3,while1()));

Scheme通過內部函數delay和force提供可選的正則序求值功能,這兩個函數提供的實際上是惰性求值的一種實現

惰性求值最常見的一種用途就是用來創建無窮數據結構

(define naturals
    (letrec ((next (lambda (n) (cons n (delay (next (+ n 1)))))))
    (next 1)))

這樣就可以用Scheme表述所有的自然數

小結

本篇首先從表達式開始,介紹了表達式(語句)中的一些基本概念;然後從討論了從彙編時代到結構化程序設計時代語言中的控制流程的演進以及發展;有了前面兩個基礎,後面就詳細的介紹了程序中的三大基本流程控制結構順序、選擇、循環(遞歸和迭代)。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※高價收購3C產品,價格不怕你比較

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!