近似と精確——《狂人C》習題解答15(第三章習題5)

3946 ワード

以前、ある農夫が死んでから15頭の牛を残していた.遺書には、「妻は牛の半分を全部分けて半分、長男は牛の半分を分けて半分、次男は牛の半分を分けて半分、次男は牛の半分を分けて半分、長女は最後の残りを分けて」とある.プログラミングで長女に牛を何頭かもらいました.
これは簡単な小学校の算数の問題です.15頭の牛の半分は7と1/2で、半分を加えると8になります.これは妻が得たものです.残り7頭7頭の牛の半分は3と1/2で、さらに半分を加えて4になるのが長男の所得です.残り3頭の3頭の牛の半分は1また1/2で、さらに半分を加えると2になります.これは次男の所得です.残り1頭のため長女は1頭を得た.
しかし、次のようなコードを書くと、最大60点しか得られません.
#include <stdio.h>

#include <stdlib.h>



#define ZONGSHU     15.  //  :  15  

#define FENPEI_BL   .5   //    :   

#define EWAI_TJ     .5   //    :   



int main( void )

{

  double qizi , zhangzi , cizi , zhangnv  ; //  、  、  、     

  double shengyu = ZONGSHU                ; //      

  

  qizi =  shengyu * FENPEI_BL +  EWAI_TJ ;     //    

  shengyu -= qizi ;                            //     

  

  zhangzi =  shengyu * FENPEI_BL +  EWAI_TJ ;  //    

  shengyu -= zhangzi ;                         //     

  

  cizi =  shengyu * FENPEI_BL +  EWAI_TJ ;     //    

  shengyu -= cizi ;                            //     

  

  zhangnv =  shengyu ;                         //  :       



  printf("     %f  
" , zhangnv ) ; system("PAUSE"); return 0; }

出力:長女は1億2000万頭の牛を手に入れた
第一に、この結果は長女が得た牛の数が約1頭に等しいことを示しているだけだからだ.第二に、コードは実際に前の算術演算プロセスを実現していない.例えばqizi=shengyu*FENPEI_BL +  EWAI_TJ ;表す意味は、前の算術演算中の正確な演算ではなく、いくつかの近似値の近似演算にすぎない.その本質と普遍的な状況について言えば、実浮動小数点タイプのデータは実数に対する近似表現にすぎないため、これは実浮動小数点タイプの演算も近似演算にすぎない.ただし,本問題では近似の精度が高く,計算結果は正確な結果と一致しているだけである.プログラムを筆算プロセスの正確なシミュレーションと見なせば,前のコードが要求に合致していないことは明らかである.コンピュータでは、整数タイプのみが整数集合のサブセットの近似表現です.したがって,筆算プロセスを正確にシミュレートするには整数タイプしか使用できない.しかし、筆算の過程は点数に及んだ.数学では、点数も正確な表現であるが、C言語ではそれに対応する「点数タイプ」はない.対応するデータ型がなければどうしますか?答えは簡単です.このタイプがなければ、このデータ型を作成します.創造性のために広大な発揮空間を提供したのはC言語の特徴と魅力であり、プログラミングの楽しみの一つでもある.分数は分子、分母の2つの部分からなり、分子、分母はいずれも整数であるため、2つの整数タイプのデータで分数を表すことができる.このようなデータに対して、C言語は直接的な演算を提供していないが、このような「点数」の演算には、自分でC言語で提供された演算シミュレーションが必要である.例えば、a/b+c/dを計算すると、1回の「+」演算では完了せず、和の分子「b*c+d*c」と和の分母「a*c」を2回に分けて計算するしかない.この方法で得られたコードは
#include <stdio.h>

#include <stdlib.h>



#define ZONGSHU_FZ     15  //     

#define ZONGSHU_FM     1   //     

#define FENPEI_BL_FZ   1   //       

#define FENPEI_BL_FM   2   //       

#define EWAI_TJ_FZ     1   //        

#define EWAI_TJ_FM     2   //        



int main( void )

{

  int  qizi_fm    , qizi_fz    , //           

       zhangzi_fm , zhangzi_fz , //          

       cizi_fm    , cizi_fz    , //            

       zhangnv_fm , zhangnv_fz ; //           

  int  shengyu_fm = ZONGSHU_FM , //        

       shengyu_fz = ZONGSHU_FZ ; //         

  

  qizi_fz  =  shengyu_fz * EWAI_TJ_FM                        //    

           +  shengyu_fm * FENPEI_BL_FM * FENPEI_BL_FZ; 

  qizi_fm  =  shengyu_fm * FENPEI_BL_FM * EWAI_TJ_FM ;      



  shengyu_fz =  shengyu_fz * qizi_fm - qizi_fz * shengyu_fm ; //     

  shengyu_fm *= qizi_fm ;                       

  

  zhangzi_fz  =  shengyu_fz * EWAI_TJ_FM                        //    

              +  shengyu_fm * FENPEI_BL_FM * FENPEI_BL_FZ; 

  zhangzi_fm  =  shengyu_fm * FENPEI_BL_FM * EWAI_TJ_FM ;      



  shengyu_fz =  shengyu_fz * zhangzi_fm - zhangzi_fz * shengyu_fm ; //     

  shengyu_fm *= zhangzi_fm ;                       

       

  cizi_fz  =  shengyu_fz * EWAI_TJ_FM                        //    

           +  shengyu_fm * FENPEI_BL_FM * FENPEI_BL_FZ; 

  cizi_fm  =  shengyu_fm * FENPEI_BL_FM * EWAI_TJ_FM ;      



  shengyu_fz =  shengyu_fz * cizi_fm - cizi_fz * shengyu_fm ; //     

  shengyu_fm *= cizi_fm ;            

  

  zhangnv_fz =  shengyu_fz ;                                   //    

  zhangnv_fm =  shengyu_fm ;



  printf("     %d %d/%d  
" , shengyu_fz/shengyu_fm , shengyu_fz % shengyu_fm , shengyu_fm ) ; system("PAUSE"); return 0; }

出力:長女は1又0/16384頭の牛をもらいました
これは正確な結果です.【注:制御文と関数理論を学習した後、後のコードをさらに改善することができます.】