File: math_ext.cpp

package info (click to toggle)
falconpl 0.9.6.9-git20120606-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 46,176 kB
  • sloc: cpp: 181,389; ansic: 109,025; yacc: 2,310; xml: 1,218; sh: 403; objc: 245; makefile: 82; sql: 20
file content (860 lines) | stat: -rw-r--r-- 22,263 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
/*
   FALCON - The Falcon Programming Language
   FILE: math.cpp

   Mathematical basic function for basic rtl.
   -------------------------------------------------------------------
   Author: Giancarlo Niccolai
   Begin: dom apr 16 2006

   -------------------------------------------------------------------
   (C) Copyright 2004: the FALCON developers (see list in AUTHORS file)

   See LICENSE file for licensing details.
*/

/** \file
   Mathematical basic function for basic rtl.
*/

/*#
   @beginmodule core
*/

#include <falcon/module.h>
#include <falcon/vm.h>

#include <math.h>
#include <errno.h>


/*#
   @funset core_math Math functions.
   @brief Functions providing math support to Falcon.

   This group includes mathematical, trigonometrical and floating point conversion
   functions.

   @beginset core_math
*/

namespace Falcon {
namespace core {

/*#
   @function log
   @brief Returns the natural logarithm of the argument.
   @param x Argument.
   @return The natural logarithm of the argument.
   @raise MathError If the argument is out of domain.

   The function may raise an error if the value cannot be
   computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_log( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }

   errno = 0;
   numeric res = log( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function log10
   @brief Returns the common (base 10) logarithm of the argument.
   @param x Argument.
   @return The common logarithm of the argument.
   @raise MathError If the argument is out of domain.

   The function may raise an error if the value cannot be
   computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_log10( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }

   errno = 0;
   numeric res = log10( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function exp
   @brief Returns exponential (e^x) of the argument.
   @param x Argument.
   @return The exponential of the argument.
   @raise MathError If the argument is out of domain.

   The function may raise an error if the value cannot be
   computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_exp( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
      return;
   }

   errno = 0;
   numeric res = exp( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function sqrt
   @brief Returns the square root of the argument.
   @param x Argument.
   @return The square root of the argument.
   @raise MathError If the argument is out of domain.

   The function may raise an error if the value cannot be
   computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_sqrt( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
      return;
   }

   errno = 0;
   numeric res = sqrt( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function mod
   @brief Returns the modulo of two arguments.
   @param x Argument.
   @param y Argument.
   @return The modulo of the two argument; x mod y.
   @raise MathError If the argument is out of domain.

   The function may raise an error if the value cannot be
   computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_mod( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );
   Item *num2 = vm->param( 1 );

   if ( num2 == 0 || ! num1->isOrdinal() || ! num2->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N,N") );
      return;
   }

   errno = 0;
   numeric res = fmod( num1->forceNumeric(), num2->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function pow
   @brief Returns the first argument elevated to the second one (x^y)
   @param x Base.
   @param y Exponent.
   @return x^y
   @raise MathError If the argument is out of domain.

   The function may raise an error if the value cannot be
   computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_pow( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );
   Item *num2 = vm->param( 1 );

   if ( num1 == 0 || ! num1->isOrdinal() || num2 == 0 || ! num2->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N,N") );
      return;
   }

   errno = 0;
   numeric res = pow( num1->forceNumeric(), num2->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function sin
   @brief Returns the sine of the argument.
   @param x Argument.
   @return The sine of the argument.
   @raise MathError If the argument is out of domain.

   The return value is expressed in radians.

   The function may raise an error if the value cannot be computed
   because of domain or overflow errors.
*/
FALCON_FUNC flc_math_sin( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }

   errno = 0;
   numeric res = sin( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function cos
   @brief Returns the cosine of the argument.
   @param x Argument.
   @return The cosine of the argument.
   @raise MathError If the argument is out of domain.

   The return value is expressed in radians.

   The function may raise an error if the value cannot be computed
   because of domain or overflow errors.
*/
FALCON_FUNC flc_math_cos( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra( "N" ) );
   }

   errno = 0;
   numeric res = cos( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function tan
   @brief Returns the tangent of the argument.
   @param x Argument.
   @return The tangent of the argument.
   @raise MathError If the argument is out of domain.

   The return value is expressed in radians.

   The function may raise an error if the value cannot be computed
   because of domain or overflow errors.
*/
FALCON_FUNC flc_math_tan( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }

   errno = 0;
   numeric res = tan( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function asin
   @brief Returns the arc sine of the argument.
   @param x Argument.
   @return The arc sine of the argument.
   @raise MathError If the argument is out of domain.

   The return value is expressed in radians.

   The function may raise an error if the value cannot be
   computed because of domain or overflow errors.
*/

FALCON_FUNC flc_math_asin( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }

   errno = 0;
   numeric res = asin( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function acos
   @brief Returns the arc cosine of the argument.
   @param x Argument.
   @return The arc cosine of the argument.
   @raise MathError If the argument is out of domain.

   This function computes the principal value of the arc cosine
   of its argument x. The value of x should be in the range [-1,1].

   The return value is expressed in radians.

   The function may raise a Math error if the value cannot
   be computed because of domain or overflow errors.
*/

FALCON_FUNC flc_math_acos( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
      return;
   }

   errno = 0;
   numeric res = acos( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function atan
   @brief Returns the arc tangent of the argument.
   @param x Argument.
   @return The arc tangent of the argument.
   @raise MathError If the argument is out of domain.

   This function computes the principal value of the arc tangent
   of its argument x. The value of x should be in the range [-1,1].

   The return value is expressed in radians.

   The function may raise a Math error if the value cannot
   be computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_atan( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
      return;
   }

   errno = 0;
   numeric res = atan( num1->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function atan2
   @brief Returns the arc tangent of x / y.
   @param x First argument.
   @param y Second argument.
   @return The arc tangent of the x / y.
   @raise MathError If the argument is out of domain.

   This function computes the principal value of the arc
   tangent of x/y, using the signs of both arguments to
   determine the quadrant of the return value.

   The return value is expressed in radians.

   The function may raise a Math error if the value cannot
   be computed because of domain or overflow errors.
*/
FALCON_FUNC flc_math_atan2( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );
   Item *num2 = vm->param( 1 );

   if ( num1 == 0 || ! num1->isOrdinal() || num2 == 0 || ! num2->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
      return;
   }

   errno = 0;
   numeric res = atan2( num1->forceNumeric(), num2->forceNumeric() );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

#define PI 3.1415926535897932384626433832795
#define E  2.7182818284590452353602874713527
/*#
   @function rad2deg
   @brief Converts an angle expressed in radians into degrees.
   @param x An angle expressed in radians.
   @return The angle converted in degrees.
*/
FALCON_FUNC flc_math_rad2deg( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
      return;
   }

   vm->retval( 180.0 / ( PI * num1->forceNumeric() ) );
}

/*#
   @function deg2rad
   @brief Converts an angle expressed in degrees into radians.
   @param x An angle expressed in degrees.
   @return The angle converted in radians.
*/
FALCON_FUNC flc_math_deg2rad( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
      return;
   }

   vm->retval( num1->forceNumeric() * PI / 180.0 );
}


/*#
   @function fract
   @brief Returns the fractional part of a number.
   @param x Argument.
   @return The fractional part of a number.

   This function returns the non-integer part of a number.
   For example,
   @code
   > fract( 1.234 )
   @endcode

   would print 0.234.
*/

FALCON_FUNC  flc_fract ( ::Falcon::VMachine *vm )
{
   Item *num = vm->param( 0 );
   if ( num->type() == FLC_ITEM_INT )
   {
      vm->retval( (int64) 0 );
   }
   else if ( num->type() == FLC_ITEM_NUM )
   {
      numeric intpart;
      vm->retval( modf( num->asNumeric(), &intpart ) );
   }
   else {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }
}

/*#
   @function fint
   @brief Returns the integer part of a floating point number as a floating point number.
   @param x Argument.
   @return A floating point number with fractional part zeroed.

   Fint function works like the core @a int function,
   but it returns a floating point number. For example,
   @b fint applied on 3.58e200 will return the same number,
   while @a int would raise a math error, as the number
   cannot be represented in a integer
   number that can store numbers up to +-2^63.

*/
FALCON_FUNC  flc_fint( ::Falcon::VMachine *vm )
{
   Item *num = vm->param( 0 );
   if ( num->type() == FLC_ITEM_INT )
   {
      vm->retval( *num );
   }
   else if ( num->type() == FLC_ITEM_NUM )
   {
         numeric n = num->asNumeric();
         numeric intpart;
         modf(n, &intpart );
         vm->retval( intpart );
   }
   else {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }
}

/*#
   @function round
   @brief Rounds a floating point to the nearest integer.
   @param x Argument.
   @return Nearest integer to x.

   Round returns the nearest integer value of a given
   floating point number. If the fractional part of the number
   is greater or equal to 0.5, the number is rounded up to the nearest
   biggest integer in absolute value, while if it's less than 0.5
   the number is rounded down to the mere integer part. For example, 1.6
   is rounded to 2, -1.6 is rounded to -2, 1.2 is rounded to 1
   and -1.2 is rounded to -1.
*/

FALCON_FUNC  flc_round ( ::Falcon::VMachine *vm )
{
   Item *num = vm->param( 0 );
   if ( num->type() == FLC_ITEM_INT )
   {
      vm->retval( *num );
   }
   else if ( num->type() == FLC_ITEM_NUM )
   {
      // Or windows or solaris, use a simple round trick.
      #if defined(_MSC_VER) || ( defined (__SVR4) && defined (__sun) )
         numeric n = num->asNumeric();
         numeric intpart;
         numeric fractpart = modf(n, &intpart );

         if ( fractpart >= 0.5 )
            vm->retval( intpart + 1 );
         else if ( fractpart <= -0.5 )
            vm->retval( intpart - 1 );
         else
            vm->retval( intpart );
      #else
         vm->retval( llround( num->asNumeric() ) );
      #endif
   }
   else {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }
}

/*#
   @function floor
   @brief Returns the smallest integer near to the given value.
   @param x Argument.
   @return The smallest integer near to the given value.

   Floor function returns the smallest integer near to a given floating
   point number. For example, floor of 1.9 is 1, and floor of -1.9 is -2.
   If an integer number is given, then the function returns the same number.
   This is similar to fint(), but in case of negative numbers @a fint would
   return the integer part; in case of -1.9 it would return -1.
*/
FALCON_FUNC  flc_floor ( ::Falcon::VMachine *vm )
{
   Item *num = vm->param( 0 );
   if ( num->type() == FLC_ITEM_INT )
   {
      vm->retval( *num );
   }
   else if ( num->type() == FLC_ITEM_NUM )
   {
      vm->retval( (int64) floor( num->asNumeric() ) );
   }
   else {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }
}

/*#
   @function ceil
   @brief Returns the greatest integer near to the given value.
   @param x Argument.
   @return The ceil value.

   Ceil function returns the highest integer near to a given floating point
   number. For example, ceil of 1.1 is 2, and ceil of -1.1 is -1. If an
   integer number is given, then the function returns the same number.
*/

FALCON_FUNC  flc_ceil ( ::Falcon::VMachine *vm )
{
   Item *num = vm->param( 0 );
   if ( num->type() == FLC_ITEM_INT )
   {
      vm->retval( *num );
   }
   else if ( num->type() == FLC_ITEM_NUM )
   {
      vm->retval( (int64) ceil( num->asNumeric() ) );
   }
   else {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }
}

/*#
   @function abs
   @brief Returns the absolute value of a number.
   @param x A number.
   @return The absolute value of the parameter.

   If the argument is an integer, then an integer is returned,
   otherwise the return value will be a floating point number.
*/

FALCON_FUNC  flc_abs ( ::Falcon::VMachine *vm )
{
   Item *num = vm->param( 0 );
   if ( num->type() == FLC_ITEM_INT )
   {
      int64 n = num->asInteger();
      vm->retval( n < 0 ? -n : n );
   }
   else if ( num->type() == FLC_ITEM_NUM )
   {
      numeric n = num->asNumeric();
      vm->retval( fabs( n ) );
   }
   else {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }
}


static numeric fact( numeric n )
{
   numeric res = 1.0;
   while( n > 0 ) {
      res *= n;
      n = n-1.0;
   }

   return res;
}

/*#
   @function factorial
   @brief Returns the factorial of the argument.
   @param x Argument.
   @return The factorial of the argument.

   The return value is expressed as a floating point value.

   @note For high values of @b x, the function may require
   exponential computational time and power.
*/
FALCON_FUNC flc_math_factorial( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );

   if ( num1 == 0 || ! num1->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N") );
   }

   numeric num = num1->forceNumeric();

   if ( num < 0 )
   {
      throw new ParamError( ErrorParam( e_param_range, __LINE__ ).origin( e_orig_runtime ) );
   }

   errno = 0;
   numeric res = fact( num );
   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function permutations
   @brief Returns the permutation of the arguments.
   @param x First argument.
   @param y Second arguments.
   @return The permutation of the arguments.

   The return value is expressed as a floating point value.

   @note For high values of @b x, the function may require
   exponential computational time and power.
*/

FALCON_FUNC flc_math_permutations( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );
   Item *num2 = vm->param( 1 );

   if ( num1 == 0 || ! num1->isOrdinal() || num2 == 0 || ! num2->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N,N") );
      return;
   }

   numeric n = num1->forceNumeric();
   numeric r = num2->forceNumeric();

   // n must be > 0, but r may be zero.
   if ( n <= 0 || r < 0)
   {
      throw new ParamError( ErrorParam( e_param_range, __LINE__ ).origin( e_orig_runtime ) );
   }

   errno = 0;
   // check to make sure numbers aren't the same
   double res = 1.0;
   double from = r == 0 ? 1 : n - r + 1;
   while ( from <= n && errno == 0 )
   {
      res *= from;
      from += 1.0;
   }

   if ( errno != 0 )
   {
      throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
   }
   else {
      vm->retval( res );
   }
}

/*#
   @function combinations
   @brief Returns the combination of the arguments.
   @param x First argument.
   @param y Second arguments.
   @return The combination of the arguments.

   The return value is expressed as a floating point value.

   @note For high values of @b x, the function may require
   exponential computational time and power.
*/
FALCON_FUNC flc_math_combinations( ::Falcon::VMachine *vm )
{
   Item *num1 = vm->param( 0 );
   Item *num2 = vm->param( 1 );

   if ( num1 == 0 || ! num1->isOrdinal() || num2 == 0 || ! num2->isOrdinal() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).extra("N,N") );
   }

   numeric n = num1->forceNumeric();
   numeric r = num2->forceNumeric();
   // check to make sure numbers aren't the same
   if ( n <= 0 || r < 0)
   {
      throw new ParamError( ErrorParam( e_param_range, __LINE__ ).origin( e_orig_runtime ) );
   }

   if ( n == r )
   {
      vm->retval( n );
   }
   else
   {
      errno = 0;
      numeric res = fact( n ) / (fact( r ) * fact(n-r));
      if ( errno != 0 )
      {
         throw new MathError( ErrorParam( e_domain, __LINE__).origin( e_orig_runtime ) );
      }
      else {
         vm->retval( res );
      }
   }
}

}
}

/* end of math.cpp */