root/trunk/orca/math.c

Revision 144, 8.8 kB (checked in by krobillard, 2 years ago)

Native arguments are now kept on the stack until after the call and the
result is now always put into a1.

Line 
1/*============================================================================
2    ORCA Interpreter
3    Copyright (C) 2005-2006  Karl Robillard
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18===========================================================================*/
19
20
21#include "os_math.h"
22#include "ovalue.h"
23#include "internal.h"
24
25
26extern int  orSeriesUsed( OValue* );
27extern void orErrorOp( const char* name, OValue* );
28
29extern void   init_genrand(unsigned long s);
30extern long   genrand_int32();
31extern double genrand_real2();
32
33
34#define PI              3.14159265358979323846
35#define DEG_TO_RAD      (PI / 180.0)
36
37
38#define REF_RADIANS     a1+1
39
40
41#define TRIG_FUNC(func) \
42    double n; \
43    if( a1->type == OT_DECIMAL ) { \
44        n = orDecimal(a1); \
45    } else { \
46        n = (double) orInt(a1); \
47        orSetTF( a1, OT_DECIMAL ); \
48    } \
49    if( orRefineSet(REF_RADIANS) ) \
50        orDecimal(a1) = func( n ); \
51    else \
52        orDecimal(a1) = func( DEG_TO_RAD * n );
53
54
55OR_NATIVE( orSineNative )
56{
57    TRIG_FUNC( mathSine )
58}
59
60
61OR_NATIVE( orCosineNative )
62{
63    TRIG_FUNC( mathCosine )
64}
65
66
67OR_NATIVE( orTangentNative )
68{
69    TRIG_FUNC( mathTan )
70}
71
72
73OR_NATIVE( orArcsineNative )
74{
75    TRIG_FUNC( mathASine )
76}
77
78
79OR_NATIVE( orArccosineNative )
80{
81    TRIG_FUNC( mathACosine )
82}
83
84
85OR_NATIVE( orArctangentNative )
86{
87    TRIG_FUNC( mathATan )
88}
89
90
91OR_NATIVE( orSquareRootNative )
92{
93    double n;
94    if( a1->type == OT_DECIMAL )
95    {
96        n = orDecimal(a1);
97    }
98    else
99    {
100        n = (double) orInt(a1);
101        orSetTF( a1, OT_DECIMAL );
102    }
103    orDecimal(a1) = mathSqrt( n );
104}
105
106
107#define REF_RAND_SEED       a1+1
108#define REF_RAND_ONLY       a1+2
109
110/* NOTE: random does not follow REBOL behavior. */
111OR_NATIVE( orRandomNative )
112{
113    if( orRefineSet(REF_RAND_SEED) )
114    {
115        unsigned long seed;
116        if( orInt(a1) )
117            seed = orInt(a1);
118        else
119            seed = randomSeed();
120        init_genrand( seed );
121    }
122    else
123    {
124        if( orIsSeries( orType(a1) ) )
125        {
126            if( orRefineSet(REF_RAND_ONLY) )
127            {
128                orError( "random/only not yet implemented " );
129                return;
130            }
131            else
132            {
133                unsigned long rn;
134                int used;
135
136                used = orSeriesUsed( a1 );
137                if( used > -1 )
138                {
139                    rn = genrand_int32();
140                    used -= a1->series.it;
141                    a1->series.it += rn % used;
142                    return;
143                }
144            }
145        }
146        else if( orIs(a1, OT_DECIMAL) )
147        {
148            orDecimal(a1) *= genrand_real2();
149            return;
150        }
151        else if( orIs(a1, OT_INTEGER) )
152        {
153            unsigned long rn = genrand_int32();
154            orInt(a1) = (rn % orInt(a1)) + 1;
155            return;
156        }
157        else if( orIs(a1, OT_LOGIC) )
158        {
159            orInt(a1) = genrand_int32() & 1;
160            return;
161        }
162        /*
163        else if( a1->type == OT_TUPLE )
164        {
165        }
166        */
167    }
168    orError( "random does not handle %s", orDatatypeName(a1->type) );
169}
170
171
172static void orOpPower( OValue* a1 )
173{
174    double x, y;
175    OValue* b = a1 + 1;
176    if( a1->type == OT_INTEGER )
177    {
178        if( b->type == OT_INTEGER )
179        {
180            int sum;
181            int n = orInt(b);
182            if( n )
183            {
184                sum = orInt(a1);
185                while( --n )
186                    sum *= orInt(a1);
187            }
188            else
189            {
190                sum = 0;
191            }
192            orResult( OT_INTEGER, sum );
193            return;
194        }
195        else if( b->type == OT_DECIMAL )
196        {
197            x = (double) orInt(a1);
198            y = orDecimal(b);
199            goto fp;
200        }
201        a1 = b;
202    }
203    else if( a1->type == OT_DECIMAL )
204    {
205        x = orDecimal(a1);
206        if( b->type == OT_INTEGER )
207        {
208            y = (double) orInt(b);
209            goto fp;
210        }
211        else if( b->type == OT_DECIMAL )
212        {
213            y = orDecimal(b);
214            goto fp;
215        }
216        a1 = b;
217    }
218    orErrorOp( "**", a1 );
219    return;
220
221fp:
222    orResultDECIMAL( pow(x, y) );
223}
224
225
226static void orOpRemainder( OValue* a1 )
227{
228    double x, y;
229    OValue* b = a1 + 1;
230    if( a1->type == OT_INTEGER )
231    {
232        if( b->type == OT_INTEGER )
233        {
234            orResult( OT_INTEGER, orInt(a1) % orInt(b) );
235            return;
236        }
237        else if( b->type == OT_DECIMAL )
238        {
239            x = (double) orInt(a1);
240            y = orDecimal(b);
241            goto fp;
242        }
243        a1 = b;
244    }
245    else if( a1->type == OT_DECIMAL )
246    {
247        x = orDecimal(a1);
248        if( b->type == OT_INTEGER )
249        {
250            y = (double) orInt(b);
251            goto fp;
252        }
253        else if( b->type == OT_DECIMAL )
254        {
255            y = orDecimal(b);
256            goto fp;
257        }
258        a1 = b;
259    }
260    orErrorOp( "//", a1 );
261    return;
262
263fp:
264    orResultDECIMAL( mathMod(x, y) );
265}
266
267
268OR_NATIVE( orComplementNative )
269{
270    switch( a1->type )
271    {
272        case OT_LOGIC:
273            orInt(a1) ^= 1;
274            break;
275
276        case OT_INTEGER:
277            orInt(a1) = ~orInt(a1);
278            break;
279
280        case OT_BITSET:
281        {
282            OString* bin = orCopyString( a1->index, a1->series.it );
283            uint8_t* it  = bin->byteArray;
284            uint8_t* end = bin->byteArray + bin->used;
285            while( it != end )
286            {
287                *it = ~(*it);
288                ++it;
289            }
290            orSetSeries( a1, orStringN(bin), 0 );
291        }
292            break;
293    }
294}
295
296
297OR_NATIVE( orAbsNative )
298{
299    switch( a1->type )
300    {
301        case OT_INTEGER:
302            if( orInt(a1) < 0 )
303                orInt(a1) = -orInt(a1);
304            break;
305
306        case OT_DECIMAL:
307            if( orDecimal(a1) < 0.0 )
308                orDecimal(a1) = -orDecimal(a1);
309            break;
310
311        case OT_PAIR:
312            if( a1->pair[0] < 0 )
313                a1->pair[0] = -a1->pair[0];
314            if( a1->pair[1] < 0 )
315                a1->pair[1] = -a1->pair[1];
316            break;
317
318        //case OT_DATE:
319        //case OT_TIME:
320        //    break;
321    }
322}
323
324
325OR_NATIVE( orNegateNative )
326{
327    switch( a1->type )
328    {
329        case OT_INTEGER:
330            orInt(a1) = -orInt(a1);
331            break;
332
333        case OT_DECIMAL:
334            orDecimal(a1) = -orDecimal(a1);
335            break;
336
337        case OT_PAIR:
338            a1->pair[0] = -a1->pair[0];
339            a1->pair[1] = -a1->pair[1];
340            break;
341
342        case OT_BITSET:
343            orComplementNative( a1 );
344            break;
345
346#ifdef OR_CONFIG_MATH3D
347        case OT_VEC2:
348        case OT_VEC3:
349            a1->vec3.x = -a1->vec3.x;
350            a1->vec3.y = -a1->vec3.y;
351            a1->vec3.z = -a1->vec3.z;
352            break;
353#endif
354
355        //case OT_TIME:
356        //    break;
357    }
358}
359
360
361#ifdef OR_CONFIG_MATH3D
362extern void orDotNative( OValue* );
363extern void orCrossNative( OValue* );
364extern void orNormalizeNative( OValue* );
365#endif
366
367void orMathNatives()
368{
369    OValue* val;
370    OContext ctx;
371
372    orGlobalCtx( ctx );
373    val = orIntern( &ctx, "pi", 2, 0 );
374    orSetTF( val, OT_DECIMAL );
375    orDecimal(val) = PI;
376
377    init_genrand( randomSeed() );
378
379    orMakeOp( orOpPower,    "**" );
380    orMakeOp( orOpRemainder,"//" );
381
382    orNative( orSineNative,         "sine"        );
383    orNative( orCosineNative,       "cosine"      );
384    orNative( orTangentNative,      "tangent"     );
385    orNative( orArcsineNative,      "arcsine"     );
386    orNative( orArccosineNative,    "arccosine"   );
387    orNative( orArctangentNative,   "arctangent"  );
388    orNative( orSquareRootNative,   "square-root" );
389    orNative( orRandomNative,       "random"      );
390    orNative( orOpPower,            "power"       );
391    orNative( orOpRemainder,        "remainder"   );
392    orNative( orComplementNative,   "complement"  );
393    orNative( orAbsNative,          "abs"         );
394    orNative( orNegateNative,       "negate"      );
395
396#ifdef OR_CONFIG_MATH3D
397    orNative( orDotNative,          "dot"         );
398    orNative( orCrossNative,        "cross"       );
399    orNative( orNormalizeNative,    "normalize"   );
400#endif
401}
402
403
404/*EOF*/
Note: See TracBrowser for help on using the browser.