Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/math/generic/trig.c

    rc0c38c7c r9adb61d  
    11/*
     2 * Copyright (c) 2015 Jiri Svoboda
    23 * Copyright (c) 2014 Martin Decky
    34 * All rights reserved.
     
    3637#include <trig.h>
    3738
    38 #define TAYLOR_DEGREE  13
     39#define TAYLOR_DEGREE_32 13
     40#define TAYLOR_DEGREE_64 21
    3941
    4042/** Precomputed values for factorial (starting from 1!) */
    41 static float64_t factorials[TAYLOR_DEGREE] = {
     43static float64_t factorials[TAYLOR_DEGREE_64] = {
    4244        1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800,
    43         479001600, 6227020800
     45        479001600, 6227020800.0L, 87178291200.0L, 1307674368000.0L,
     46        20922789888000.0L, 355687428096000.0L, 6402373705728000.0L,
     47        121645100408832000.0L, 2432902008176640000.0L, 51090942171709440000.0L
    4448};
    4549
    46 /** Sine approximation by Taylor series
     50/** Sine approximation by Taylor series (32-bit floating point)
    4751 *
    4852 * Compute the approximation of sine by a Taylor
     
    5660 *
    5761 */
    58 static float64_t taylor_sin(float64_t arg)
    59 {
    60         float64_t ret = 0;
    61         float64_t nom = 1;
    62        
    63         for (unsigned int i = 0; i < TAYLOR_DEGREE; i++) {
     62static float32_t taylor_sin_32(float32_t arg)
     63{
     64        float32_t ret = 0;
     65        float32_t nom = 1;
     66       
     67        for (unsigned int i = 0; i < TAYLOR_DEGREE_32; i++) {
    6468                nom *= arg;
    6569               
     
    7377}
    7478
    75 /** Cosine approximation by Taylor series
     79/** Sine approximation by Taylor series (64-bit floating point)
     80 *
     81 * Compute the approximation of sine by a Taylor
     82 * series (using the first TAYLOR_DEGREE terms).
     83 * The approximation is reasonably accurate for
     84 * arguments within the interval [-pi/4, pi/4].
     85 *
     86 * @param arg Sine argument.
     87 *
     88 * @return Sine value approximation.
     89 *
     90 */
     91static float64_t taylor_sin_64(float64_t arg)
     92{
     93        float64_t ret = 0;
     94        float64_t nom = 1;
     95       
     96        for (unsigned int i = 0; i < TAYLOR_DEGREE_64; i++) {
     97                nom *= arg;
     98               
     99                if ((i % 4) == 0)
     100                        ret += nom / factorials[i];
     101                else if ((i % 4) == 2)
     102                        ret -= nom / factorials[i];
     103        }
     104       
     105        return ret;
     106}
     107
     108/** Cosine approximation by Taylor series (32-bit floating point)
    76109 *
    77110 * Compute the approximation of cosine by a Taylor
     
    85118 *
    86119 */
    87 static float64_t taylor_cos(float64_t arg)
    88 {
    89         float64_t ret = 1;
    90         float64_t nom = 1;
    91        
    92         for (unsigned int i = 0; i < TAYLOR_DEGREE; i++) {
     120static float32_t taylor_cos_32(float32_t arg)
     121{
     122        float32_t ret = 1;
     123        float32_t nom = 1;
     124       
     125        for (unsigned int i = 0; i < TAYLOR_DEGREE_32; i++) {
    93126                nom *= arg;
    94127               
     
    102135}
    103136
    104 /** Sine value for values within base period
     137/** Cosine approximation by Taylor series (64-bit floating point)
     138 *
     139 * Compute the approximation of cosine by a Taylor
     140 * series (using the first TAYLOR_DEGREE terms).
     141 * The approximation is reasonably accurate for
     142 * arguments within the interval [-pi/4, pi/4].
     143 *
     144 * @param arg Cosine argument.
     145 *
     146 * @return Cosine value approximation.
     147 *
     148 */
     149static float64_t taylor_cos_64(float64_t arg)
     150{
     151        float64_t ret = 1;
     152        float64_t nom = 1;
     153       
     154        for (unsigned int i = 0; i < TAYLOR_DEGREE_64; i++) {
     155                nom *= arg;
     156               
     157                if ((i % 4) == 1)
     158                        ret -= nom / factorials[i];
     159                else if ((i % 4) == 3)
     160                        ret += nom / factorials[i];
     161        }
     162       
     163        return ret;
     164}
     165
     166/** Sine value for values within base period (32-bit floating point)
    105167 *
    106168 * Compute the value of sine for arguments within
     
    114176 *
    115177 */
    116 static float64_t base_sin(float64_t arg)
     178static float32_t base_sin_32(float32_t arg)
    117179{
    118180        unsigned int period = arg / (M_PI / 4);
     
    120182        switch (period) {
    121183        case 0:
    122                 return taylor_sin(arg);
     184                return taylor_sin_32(arg);
    123185        case 1:
    124186        case 2:
    125                 return taylor_cos(arg - M_PI / 2);
     187                return taylor_cos_32(arg - M_PI / 2);
    126188        case 3:
    127189        case 4:
    128                 return -taylor_sin(arg - M_PI);
     190                return -taylor_sin_32(arg - M_PI);
    129191        case 5:
    130192        case 6:
    131                 return -taylor_cos(arg - 3 * M_PI / 2);
     193                return -taylor_cos_32(arg - 3 * M_PI / 2);
    132194        default:
    133                 return taylor_sin(arg - 2 * M_PI);
    134         }
    135 }
    136 
    137 /** Cosine value for values within base period
     195                return taylor_sin_32(arg - 2 * M_PI);
     196        }
     197}
     198
     199/** Sine value for values within base period (64-bit floating point)
     200 *
     201 * Compute the value of sine for arguments within
     202 * the base period [0, 2pi]. For arguments outside
     203 * the base period the returned values can be
     204 * very inaccurate or even completely wrong.
     205 *
     206 * @param arg Sine argument.
     207 *
     208 * @return Sine value.
     209 *
     210 */
     211static float64_t base_sin_64(float64_t arg)
     212{
     213        unsigned int period = arg / (M_PI / 4);
     214       
     215        switch (period) {
     216        case 0:
     217                return taylor_sin_64(arg);
     218        case 1:
     219        case 2:
     220                return taylor_cos_64(arg - M_PI / 2);
     221        case 3:
     222        case 4:
     223                return -taylor_sin_64(arg - M_PI);
     224        case 5:
     225        case 6:
     226                return -taylor_cos_64(arg - 3 * M_PI / 2);
     227        default:
     228                return taylor_sin_64(arg - 2 * M_PI);
     229        }
     230}
     231
     232/** Cosine value for values within base period (32-bit floating point)
    138233 *
    139234 * Compute the value of cosine for arguments within
     
    147242 *
    148243 */
    149 static float64_t base_cos(float64_t arg)
     244static float32_t base_cos_32(float32_t arg)
    150245{
    151246        unsigned int period = arg / (M_PI / 4);
     
    153248        switch (period) {
    154249        case 0:
    155                 return taylor_cos(arg);
     250                return taylor_cos_32(arg);
    156251        case 1:
    157252        case 2:
    158                 return -taylor_sin(arg - M_PI / 2);
     253                return -taylor_sin_32(arg - M_PI / 2);
    159254        case 3:
    160255        case 4:
    161                 return -taylor_cos(arg - M_PI);
     256                return -taylor_cos_32(arg - M_PI);
    162257        case 5:
    163258        case 6:
    164                 return taylor_sin(arg - 3 * M_PI / 2);
     259                return taylor_sin_32(arg - 3 * M_PI / 2);
    165260        default:
    166                 return taylor_cos(arg - 2 * M_PI);
    167         }
    168 }
    169 
    170 /** Double precision sine
     261                return taylor_cos_32(arg - 2 * M_PI);
     262        }
     263}
     264
     265/** Cosine value for values within base period (64-bit floating point)
     266 *
     267 * Compute the value of cosine for arguments within
     268 * the base period [0, 2pi]. For arguments outside
     269 * the base period the returned values can be
     270 * very inaccurate or even completely wrong.
     271 *
     272 * @param arg Cosine argument.
     273 *
     274 * @return Cosine value.
     275 *
     276 */
     277static float64_t base_cos_64(float64_t arg)
     278{
     279        unsigned int period = arg / (M_PI / 4);
     280       
     281        switch (period) {
     282        case 0:
     283                return taylor_cos_64(arg);
     284        case 1:
     285        case 2:
     286                return -taylor_sin_64(arg - M_PI / 2);
     287        case 3:
     288        case 4:
     289                return -taylor_cos_64(arg - M_PI);
     290        case 5:
     291        case 6:
     292                return taylor_sin_64(arg - 3 * M_PI / 2);
     293        default:
     294                return taylor_cos_64(arg - 2 * M_PI);
     295        }
     296}
     297
     298/** Sine (32-bit floating point)
    171299 *
    172300 * Compute sine value.
     
    177305 *
    178306 */
     307float32_t float32_sin(float32_t arg)
     308{
     309        float32_t base_arg = fmod_f32(arg, 2 * M_PI);
     310       
     311        if (base_arg < 0)
     312                return -base_sin_32(-base_arg);
     313       
     314        return base_sin_32(base_arg);
     315}
     316
     317/** Sine (64-bit floating point)
     318 *
     319 * Compute sine value.
     320 *
     321 * @param arg Sine argument.
     322 *
     323 * @return Sine value.
     324 *
     325 */
    179326float64_t float64_sin(float64_t arg)
    180327{
    181         float64_t base_arg = fmod(arg, 2 * M_PI);
     328        float64_t base_arg = fmod_f64(arg, 2 * M_PI);
    182329       
    183330        if (base_arg < 0)
    184                 return -base_sin(-base_arg);
    185        
    186         return base_sin(base_arg);
    187 }
    188 
    189 /** Double precision cosine
     331                return -base_sin_64(-base_arg);
     332       
     333        return base_sin_64(base_arg);
     334}
     335
     336/** Cosine (32-bit floating point)
    190337 *
    191338 * Compute cosine value.
     
    196343 *
    197344 */
     345float32_t float32_cos(float32_t arg)
     346{
     347        float32_t base_arg = fmod_f32(arg, 2 * M_PI);
     348       
     349        if (base_arg < 0)
     350                return base_cos_32(-base_arg);
     351       
     352        return base_cos_32(base_arg);
     353}
     354
     355/** Cosine (64-bit floating point)
     356 *
     357 * Compute cosine value.
     358 *
     359 * @param arg Cosine argument.
     360 *
     361 * @return Cosine value.
     362 *
     363 */
    198364float64_t float64_cos(float64_t arg)
    199365{
    200         float64_t base_arg = fmod(arg, 2 * M_PI);
     366        float64_t base_arg = fmod_f64(arg, 2 * M_PI);
    201367       
    202368        if (base_arg < 0)
    203                 return base_cos(-base_arg);
    204        
    205         return base_cos(base_arg);
     369                return base_cos_64(-base_arg);
     370       
     371        return base_cos_64(base_arg);
    206372}
    207373
Note: See TracChangeset for help on using the changeset viewer.