Advertisement
Guest User

2. projekt IZP2008

a guest
Oct 27th, 2012
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.50 KB | None | 0 0
  1. /*
  2.  * Soubor:  proj2.c
  3.  * Datum:   25.11.2008
  4.  * Autor:   kolemjdouci
  5.  * Projekt: Iteracni vypocty, projekt è. 2 pro pøedmìt IZP
  6.  * Popis:   vyocty funkci ln a tangens a take prevadi zrychleni
  7.  *          na polohu a naopak
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <stdbool.h>
  15. #include <math.h>
  16. #include <errno.h>
  17. #include <limits.h>
  18.  
  19.  
  20. #define absolute(val)  ( ( (val) >=0)? (val) : -(val) )
  21. #define MIN_ACC 1e-15
  22. #define TIME_SPAN 0.5
  23. #define TIME_SPAN_SQ_MUL_HALF 0.125 // "(time span sqared)*1/2"
  24. #define DIMENSION 3 // 3 rozmery nekdy nestaci :D
  25.  
  26. /** konstanty */
  27. const double IZP_E = 2.7182818284590452354;        // e
  28. const double IZP_PI = 3.14159265358979323846;      // pi
  29. const double IZP_2PI = 6.28318530717958647692;     // 2*pi
  30. const double IZP_PI_2 = 1.57079632679489661923;    // pi/2
  31. const double IZP_PI_4 = 0.78539816339744830962;    // pi/4
  32. //
  33.  
  34. /** hlavicky fci */
  35. int tan_converg(double *);
  36. int sin_converg(double *);
  37. unsigned int nat_log_converg(double *, int *);
  38. void printCode(int);
  39. int signum(double);
  40. double sinus(double, double);
  41. double cosin(double, double);
  42. double nat_log(double, double);
  43. struct param getParams(int, char *[]);
  44. //double accel2position(double, TRADAR *); jak se vlastne delaji prototypy se
  45. //double position2accel(double, TRADAR *); strukturama v argumentu?
  46. void math_cycle(int,double );
  47. void rad_cykl(int);
  48.  
  49. /** struktura pro hodnoty pozice a rychlost radaru */
  50. typedef struct radar{
  51.   double position;
  52.   double speed;
  53. } TRADAR;
  54.  
  55. /** struktura pro prenos parametru shellu */
  56. typedef struct param{
  57.   unsigned int mode;
  58.   double acc;
  59.   unsigned int state;
  60. } TPARAM;
  61.  
  62.  
  63. /** kody jednotlivych modu programu */
  64. enum tparams
  65. { //nazvy jsou snad pochopitelne
  66.   RAD1 = 0,
  67.   RAD2,
  68.   LN,
  69.   TAN,
  70.   SIN,
  71.   COS,
  72. };
  73.  
  74. /** Kódy chyb a stavù programu */
  75. enum tcodes
  76. {
  77.   EOK = 0,     /**< vse v poradku */
  78.   ECLWRONG,    /**< Chybný pøíkazový øádek */
  79.   EACCWRONG,   /**< Chybna presnost */
  80.   EUNKNOWN,    /**< Neznámá chyba */
  81.   CHELP,       /**< Tisk napovedy */
  82.   ENDCODE,     /**< zará¾ka */
  83. };
  84.  
  85.  
  86. /** Pole textových øetìzcù vypisovaných funkcí printCode. pouzite z proj1 */
  87. const char *CODEMSG[] =
  88. {
  89.   /* EOK */
  90.   "V¹e v poøádku.\n",
  91.   /* ECLWRONG */
  92.   "Chybné parametry pøíkazového øádku!\n",
  93.   /* EACCWRONG */
  94.   "Jako presnost vypoctu muze figurovat pouze kladne realne cislo\n",
  95.   /* EUNKNOWN */
  96.   "Nastala nepøedvídaná chyba! Vypnìte poèítaè a rychle uteète.\n",
  97.   /* CHELP */
  98.   "Program Iteracni vypocty\n"
  99.   "Autor: kolemjdouci - 2008\n"
  100.   "Program provádí ...\n"
  101.   "Pou¾ití: proj1 -h\n"
  102.   "         proj1 -ln double (presnost)\n"
  103.   "         proj1 -tan double (presnost)\n"
  104.   "         proj1 -sin double (presnost)\n"
  105.   "         proj1 -cos double (presnost)\n"
  106.   "         proj1 -radar1\n"
  107.   "         proj1 -radar2\n"
  108.   "Popis parametrù:\n"
  109.   "  [...]\n"
  110. };
  111.  
  112. /**
  113.  * "extended_strtod" - nastavba strtod, pri jakemkoliv problemu vraci NAN
  114.  * @param *string - jaky retezec se pravadi na double
  115.  * @return pri ne uplne korektnim vstupu vraci NAN, jinak stejne jako strtod
  116.  */
  117. double ext_strtod(char *string)
  118. {
  119.   char *endptr;
  120.   double value;
  121.   errno=0;
  122.   value = strtod(string, &endptr);
  123.   if (errno != 0 || *endptr != '\0' )
  124.   {
  125.     value=0.0/0.0 ;
  126.   }
  127.   return value ;
  128. }
  129.  
  130.  
  131. /**
  132.  * Zpracuje argumenty pøíkazového øádku a vrátí je ve struktuøe TParams.
  133.  * Pokud je formát argumentù chybný, ukonèí program s chybovým kódem.
  134.  * @param argc Poèet argumentù.
  135.  * @param argv Pole textových øetìzcù s argumenty.
  136.  * @return Vrací analyzované argumenty pøíkazového øádku.
  137.  */
  138. TPARAM getParams(int argc, char *argv[])
  139. {
  140.   TPARAM result =
  141.   { // inicializace struktury
  142.     .mode = 0,
  143.     .acc = 0,
  144.     .state = EOK,
  145.   };
  146.   if (argc == 2)
  147.   { // jeden parametr
  148.     if (strcmp("-h", argv[1]) == 0)
  149.     {// tisk nápovìdy
  150.       result.state = CHELP;
  151.     }
  152.     else if (strcmp("-radar1", argv[1]) == 0)
  153.     {
  154.       result.mode = RAD1 ;
  155.     }
  156.     else if (strcmp("-radar2", argv[1]) == 0)
  157.     {
  158.       result.mode = RAD2 ;
  159.     }
  160.     else
  161.     {
  162.       result.state = ECLWRONG ;
  163.     }
  164.   }
  165.   else if (argc == 3)
  166.   { // dva parametry
  167.  
  168.     if ( (strcmp("-ln", argv[1]) == 0))
  169.     {
  170.       result.mode = LN ;
  171.     }
  172.     else if ( (strcmp("-tan", argv[1]) == 0))
  173.     {
  174.       result.mode = TAN ;
  175.     }
  176.     else if ( (strcmp("-sin", argv[1]) == 0))
  177.     {
  178.       result.mode = SIN ;
  179.     }
  180.     else if ( (strcmp("-cos", argv[1]) == 0))
  181.     {
  182.       result.mode = COS ;
  183.     }
  184.     else
  185.     {
  186.       result.state = ECLWRONG ;
  187.     }
  188.     /** kontrola zadane presnosti */
  189.     if (result.state!=ECLWRONG)
  190.     {
  191.       char *str;
  192.       double val;
  193.       str=argv[2];
  194.       val=ext_strtod(str);
  195.       if (val==0.0/0.0 || val<=0 || !(isfinite(val)) )
  196.       {
  197.         result.state = EACCWRONG ;
  198.       }
  199.       else
  200.       {
  201.         result.acc = val ;
  202.       }
  203.     }
  204.   }
  205.   else
  206.   { // chybný poèet parametrù
  207.     result.state = ECLWRONG;
  208.   }
  209.   return result;
  210. }
  211.  
  212. /**
  213.  * premistuje tangens do intervalu nejlepsi konvergence,
  214.  * skoro to samy jako sinus, jenom o jedne presun min
  215.  * @param *x - hodnota s kterou pocitame v radianech
  216.  * @return - vysledne znamenko
  217.  */
  218. int tan_converg(double *x)
  219. {
  220.   int sign;
  221.   sign = signum(*x);
  222.   *x = absolute(*x);
  223.   if ( *x >= IZP_PI)
  224.   {
  225.     double help;
  226.     help = floor(*x / IZP_PI);
  227.     *x = *x - ( help * IZP_PI );
  228.   }
  229.   if ( *x >= IZP_PI_2)
  230.   {
  231.       *x = IZP_PI - *x;
  232.       sign = -sign ;
  233.   }
  234.   if (*x == 0) // problemy se zapornou nulou
  235.   {
  236.       return 0;
  237.   }
  238.   return sign;
  239. }
  240.  
  241. /**
  242.  * premistuje sinus do intervalu nejlepsi konvergence
  243.  * nejdrive premisti na interval <0;inf) (l. 253-254)
  244.  * pak na interval <0;2pi) (l. 255-260)
  245.  * pak na interval <0;pi) (l. 261-265)
  246.  * a nakonec na interval <0;pi/2) (l. 266-269)
  247.  * @param *x - hodnota s kterou pocitame v radianech
  248.  * @return - vysledne znamenko
  249.  */
  250. int sin_converg(double *x)
  251. {
  252.   int sign;
  253.   sign = signum(*x);
  254.   *x = absolute(*x);
  255.   if ( *x >= IZP_2PI)
  256.   {
  257.     double help;
  258.     help = floor(*x / IZP_2PI);
  259.     *x = *x - ( help * IZP_2PI );
  260.   }
  261.   if ( *x >= IZP_PI)
  262.   {
  263.     sign = -sign;
  264.     *x = *x - IZP_PI ;
  265.   }
  266.   if ( *x >= IZP_PI_2)
  267.   {
  268.     *x = IZP_PI - *x;
  269.   }
  270.   if (*x == 0) // problemy se zapornou nulou
  271.   {
  272.       return 0;
  273.   }
  274.   return sign;
  275. }
  276.  
  277. /**
  278.  * funkce tangens
  279.  * prakticky vola pouze podil sinu a cosinu
  280.  * @param x - tangens ceho se pocita
  281.  * @param acc - s jakou presnosti
  282.  * @return vraci hodnotu fce tan, mimo def. obor NAN
  283.  */
  284. double tangens(double x, double acc)
  285. {
  286.   if ( !(isfinite(x)) )
  287.   {
  288.     return 0.0/0.0;
  289.   }
  290.   acc=acc/100 ;
  291.   int sign;
  292.   sign = tan_converg(&x);
  293.   if (x==IZP_PI_2)
  294.   {
  295.     return 0.0/0.0;
  296.   }
  297. /* - tahle heuristika se prokazala zalostne neucinou
  298.   else if ( x>1.5 )
  299.   { // tan(2x)=2*tan(x)/(1-(tan(x)^2))
  300.     double help;
  301.     help=tangens(x/2,acc) ;
  302.     x = (2*help)/(1-help*help) ;
  303.   } */
  304.   else
  305.   {
  306.     x = sinus(x, acc)/cosin(x, acc);
  307.   }
  308.   return x*sign;
  309. }
  310.  
  311. /**
  312.  * Vytiskne kód chyby nebo text popisující stav programu.
  313.  * @param code - kód chyby nebo stavu programu
  314.  */
  315. void printCode(int code)
  316. {
  317.   if (code < EOK || code >= ENDCODE)
  318.   { code = EUNKNOWN; }
  319.  
  320.   FILE *outstream = stdout;
  321.   if (code <= EUNKNOWN)
  322.   {
  323.     outstream = stderr;
  324.   }
  325.  
  326.   fprintf(outstream, "%s", CODEMSG[code]);
  327. }
  328.  
  329. /**
  330.  * fce signum... puvodne jsem nechtel vubec pouzivat matematickou knihovnu
  331.  * @param x - ktereho cisla chci signum
  332.  * @return 1/0/-1 v zavislosti na vysledku
  333.  */
  334. int signum(double x)
  335. {
  336.   if ( x == 0 )
  337.   {
  338.     return 0;
  339.   }
  340.   else if ( x > 0 )
  341.   {
  342.     return 1;
  343.   }
  344.   else
  345.   {
  346.     return -1;
  347.   }
  348. }
  349.  
  350. /**
  351.  * radar prevadejici pozici na zrychleni
  352.  * vzorec:
  353.  * nova draha= puvodni draha + puvodni rychlost*ubehly cas + 0.5*zrychleni
  354.  *             *ubehly cas na druhou
  355.  * nova rychlost= puvodni rychlost + zrychleni*ubehly cas
  356.  * @param accel - hodnota zrychleni, kterou prevadim
  357.  * @param *rad -pointer na strukturu, kde ukladam prubeznou polohu a rychlost
  358.  * @return - aktualni pozice
  359.  */
  360. double accel2position(double accel, TRADAR *rad)
  361. {
  362.   if (!(isfinite(accel)))
  363.   {
  364.     return 0.0/0.0 ;
  365.   }
  366.   rad->position=(*rad).position+(*rad).speed/2 +TIME_SPAN_SQ_MUL_HALF * accel;
  367.   rad->speed = TIME_SPAN * accel + (*rad).speed;
  368.   return (*rad).position;
  369. }
  370.  
  371. /**
  372.  * radar prevadejici z pozice na zrychleni
  373.  * vzorec, viz. predchozi radar
  374.  * @param position - poloha, kterou prevadim an zrcyhleni
  375.  * @param *rad -pointer na strukturu, kde ukladam prubeznou polohu a rychlost
  376.  * @return aktualni zrychleni
  377.  */
  378. double position2accel(double position, TRADAR *rad)
  379. { // stx = s0 + v0t + 0.5 a t^2 && vtx = v0 + at
  380.   double accel;
  381.   if (!(isfinite(position)))
  382.   {
  383.     return 0.0/0.0 ;
  384.   }
  385.   accel = ((position-(*rad).position) - TIME_SPAN * (*rad).speed) / TIME_SPAN_SQ_MUL_HALF ;
  386.   rad->speed = (*rad).speed + accel * TIME_SPAN ;
  387.   rad->position = position;
  388.   return accel ;
  389. }
  390.  
  391. /**
  392.  * cyklus nacitani a tisku hodnot pro radary
  393.  * @param mode - ktery ze dvou radaru se pouzije
  394.  */
  395. void rad_cykl(int mode)
  396. {
  397.   int i = 0;
  398.   int j = 1;
  399.   TRADAR radar[DIMENSION];
  400.   radar[0].position=0.0 , radar[0].speed=0.0 ;
  401.   while (j < DIMENSION)
  402.   { // nulovani hodnot pro vsechny radary (prvky pole radaru)
  403.     radar[j]=radar[0];
  404.     j++;
  405.   }
  406.   double (*rad_fce)(double,TRADAR *); // pointer na pozadovanou fci
  407.   rad_fce = (mode==RAD1)? accel2position : position2accel ;
  408.   char buffer[128];
  409.   double out,in;
  410.   while ( fscanf(stdin,"%127s", buffer) != EOF )
  411.   {
  412.     in = ext_strtod(buffer);
  413.     out = rad_fce(in,&radar[i]);
  414.     printf("%.10le\n", out);
  415.     i++;
  416.     i %= DIMENSION;
  417.     //i = (++i) % DIMENSION; - nechapu proc tohle nefungovalo
  418.   }
  419. }
  420.  
  421. /**
  422.  * cyklus nacitani a tisku hodnot pro matematicke fce
  423.  * @param mode - ktera funkce se pouzije
  424.  * @param acc - presnost s jakou se bude pocitat
  425.  */
  426. void math_cycle(int mode,double acc)
  427. {
  428.   double (*mat_fce)(double, double);
  429.   switch (mode)
  430.   { // ktera funkce se bude pouzivat
  431.     case LN : mat_fce = nat_log; break;
  432.     case TAN : mat_fce = tangens; break;
  433.     case SIN : mat_fce = sinus; break;
  434.     case COS : mat_fce = cosin; break;
  435.   }
  436.   double in;
  437.   double out;
  438.   char buffer[128];
  439.   while ( fscanf(stdin,"%127s", buffer) != EOF )
  440.   {
  441.     in = ext_strtod(buffer);
  442.     out = mat_fce(in,acc);
  443.     printf("%.10le\n", out);
  444.   }
  445. }
  446.  
  447.  
  448.  
  449. /**
  450.  * vypocet fce sinus, za pomoci taylorova rozvoje pro sin(x)
  451.  * @param x - sinus ceho se ma vypocitat
  452.  * @param acc - (accuracy) - s jakou presnosti
  453.  * @return hodnota fce
  454.  */
  455. double sinus(double x, double acc)
  456. {
  457.   int sign;
  458.   if ( !(isfinite(x)) )
  459.   {
  460.     return 0.0/0.0;
  461.   }
  462.   sign = sin_converg(& x);
  463.   /** dal je to obdobne, jako vypocet cosinu na demonstracnim cviceni */
  464.   double sum, x_sqd, help;
  465.   x_sqd = x * x;
  466.   help = x;
  467.   sum = help;
  468.   acc = (acc< MIN_ACC && acc>0)? acc : MIN_ACC;
  469.   int j=3;
  470.   do {
  471.     help *= -x_sqd/ (j * (j-1));
  472.     sum += help;
  473.     j += 2;
  474.   } while( absolute(help) > acc);
  475.   return (sum * sign);
  476. }
  477.  
  478.  
  479. /**
  480.  * nebyt toho, ze potrebuju pointer na tuto fci,
  481.  * stacilo by mi makro, viz. fce sinus
  482.  */
  483. double cosin(double x, double acc)
  484. {
  485.   return sinus(x + IZP_PI_2, acc );
  486. }
  487.  
  488.  
  489. /**
  490.  * tady predelavam logaritmus do intervallu nejlepsi konvergence
  491.  * pro mala cisla pouzivam vzorec ln(x^y)=y*ln(x) (y=-1)
  492.  * pro vetsi nez 1.5 zase ln(a*b)=ln(a)+ln(b) (b=e)
  493.  * @param *x - pointer na cislo, ktere mam dostat do inter. nejlepsi. konverg.
  494.  * @param *sign - urcuje, zda se bude navratova hodnota pozdeji k vysledku
  495.  *                pricitat, nebo od nej odecitat, viz. vzorec pro mala cisla
  496.  * @return kolikrat tam bude "b" z druheho vzroce
  497.  */
  498. unsigned int nat_log_converg(double *x, int *sign)
  499. {
  500.   if (*x<0.55)
  501.   {
  502.     *x = 1.0 / *x ;
  503.     *sign = -1 ;
  504.   }
  505.   int shift = 0;
  506.   while ( *x > 1.5 ) // 1.5/e ~= 0.552
  507.   {
  508.     *x = *x / IZP_E ;
  509.     shift++ ;
  510.   }
  511.   *x -= 1 ;
  512.   return shift;
  513. }
  514.  
  515.  
  516. /**
  517.  * vypocet fce ln pocitam na tomto intervalu hodnotu fce s co nejnizsim
  518.  * poctem operaci  za pomoci taylorova rozvoje pro ln(x+1)
  519.  * @param x - ln ceho se ma vypocitat
  520.  * @param acc - (accuracy) - s jakou presnosti
  521.  * @return vypocitana hodnota
  522.  */
  523. double nat_log(double x, double acc)
  524. {
  525.   if (x<0 || isnan(x) )
  526.   { // kdy vratit NaN
  527.     return 0.0/0.0 ;
  528.   }
  529.   if ( isinf(x) )
  530.   { // kdy vratit Inf
  531.     return 1.0/0.0 ;
  532.   }
  533.   if (x==0)
  534.   { // kdy vratit -Inf
  535.     return -(1.0/0.0) ;
  536.   }
  537.   unsigned int shift;
  538.   int sign = 1;
  539.   shift = nat_log_converg(&x, &sign);
  540.   acc = (acc< MIN_ACC && acc>0)? acc : MIN_ACC;
  541.   double sum, help, diff;
  542.   sum = x ;
  543.   help = x;
  544.   diff = x;
  545.   int i = 1;
  546.   while ( absolute(diff) > acc)
  547.   {
  548.     i ++ ;
  549.     help *= -x ;
  550.     diff = help/i ;
  551.     sum += diff ;
  552.   }
  553.   return sign*(sum+shift) ;
  554. }
  555.  
  556.  
  557. /////////////////////////////////////////////////////////////////
  558. /**
  559.  * Hlavní program.
  560.  * nejdriv vola fci na analyzu argument cmd, pak pripadne skonci
  561.  * podle nich zavola bud funkci na radary nebo na mat. fce
  562.  */
  563. int main(int argc, char *argv[])
  564. {
  565.  
  566.   TPARAM params = getParams(argc, argv);
  567.   if (params.state != EOK)
  568.   { // nìco nestandardního
  569.     printCode(params.state);
  570.     return (params.state == CHELP)? EXIT_SUCCESS : EXIT_FAILURE;
  571.   }
  572.   if (params.mode>RAD2)
  573.   {
  574.     math_cycle(params.mode,params.acc);
  575.   }
  576.   else
  577.   {
  578.     rad_cykl(params.mode);
  579.   }
  580.  
  581. //    printf("%.13Le\n\n", (double)( ((double)0) * ((int)(-1)) ) ); // = -0.0
  582.     return EXIT_SUCCESS;
  583. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement