1//
2//  EMResponder.m
3//  EdenMath
4//
5//  Created by admin on Thu Feb 21 2002.
6//  Copyright (c) 2002-2004 Edenwaith. All rights reserved.
7//
8
9#import "EMResponder.h"
10
11#include <math.h>
12#include <stdlib.h>
13
14#ifdef GNUSTEP
15#include <time.h>
16#endif
17
18@implementation EMResponder
19
20
21// -------------------------------------------------------
22// (id) init
23// -------------------------------------------------------
24- (id) init
25{
26    current_value	= 0.0;
27    previous_value	= 0.0;
28    op_type	 	= NO_OP;
29    angle_type 		= DEGREE;
30    e_value		= M_E; 		// 2.7182818285
31    trailing_digits 	= 0;
32    isNewDigit		= YES;
33
34    return self;
35}
36
37// -------------------------------------------------------
38// (double) getCurrentValue
39// Simple return function which returns the current
40// value
41// -------------------------------------------------------
42- (double) getCurrentValue
43{
44    return current_value;
45}
46
47
48// -------------------------------------------------------
49// (int) getTrailingDigits
50// Simple return function which returns the number of
51// trailing digits on the currently displayed number
52// so the proper amount of precision can be displayed.
53// Limit the number of trailing digits precision so odd
54// errors don't occur.
55// -------------------------------------------------------
56- (int) getTrailingDigits
57{
58    if (trailing_digits == 0)
59    {
60        trailing_digits = 0;
61    }
62    else if (trailing_digits > 10)
63    {
64        trailing_digits = 10;
65    }
66
67    return trailing_digits;
68}
69
70// -------------------------------------------------------
71// (void) setCurrentValue:(double)num
72// -------------------------------------------------------
73- (void) setCurrentValue:(double)num
74{
75    current_value = num;
76}
77
78
79// -------------------------------------------------------
80// (void) setState:(NSDictionary *)stateDictionary
81// -------------------------------------------------------
82- (void)setState:(NSDictionary *)stateDictionary
83{
84    current_value 	= [[stateDictionary objectForKey: @"current_value"] doubleValue];
85    previous_value   	= [[stateDictionary objectForKey: @"previous_value"] doubleValue];
86    op_type     	= [[stateDictionary objectForKey: @"op_type"] intValue];
87    trailing_digits   	= [[stateDictionary objectForKey: @"trailing_digits"] intValue];
88    isNewDigit    	= [[stateDictionary objectForKey: @"isNewDigit"] boolValue];
89}
90
91// -------------------------------------------------------
92// (NSDictionary *) state
93// -------------------------------------------------------
94- (NSDictionary *)state
95{
96    NSDictionary *stateDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
97        [NSNumber numberWithDouble: current_value], @"current_value",
98        [NSNumber numberWithDouble: previous_value], @"previous_value",
99        [NSNumber numberWithInt: op_type], @"op_type",
100        [NSNumber numberWithInt: trailing_digits], @"trailing_digits",
101        [NSNumber numberWithBool: isNewDigit], @"isNewDigit",
102        nil];
103    return stateDictionary;
104}
105
106// -------------------------------------------------------
107// (void)newDigit:(int)digit
108// -------------------------------------------------------
109- (void)newDigit:(int)digit
110{
111
112    if (isNewDigit)
113    {
114        previous_value = current_value;
115        isNewDigit  = NO;
116        current_value = digit;
117    }
118    else
119    {
120        BOOL negative = NO;
121        if (current_value < 0)
122        {
123            current_value = - current_value;
124            negative = YES;
125        }
126
127        if (trailing_digits == 0)
128        {
129            current_value = current_value * 10 + digit;
130        }
131        else
132        {
133            current_value = current_value + (digit/pow(10.0, trailing_digits));
134
135            trailing_digits++;
136        }
137
138        if (negative == YES)
139        {
140            current_value = - current_value;
141        }
142    }
143}
144
145// -------------------------------------------------------
146// (void) period
147// -------------------------------------------------------
148- (void)period
149{
150    if (isNewDigit)
151    {
152        current_value = 0.0;
153        isNewDigit = NO;
154    }
155    if (trailing_digits == 0)
156    {
157        trailing_digits = 1;
158    }
159}
160
161// -------------------------------------------------------
162// (void) pi
163// Display the constant pi (3.141592653589793)
164// -------------------------------------------------------
165- (void) pi
166{
167    current_value 	= M_PI;
168    trailing_digits 	= 0;
169    isNewDigit 		= YES;
170}
171
172// -------------------------------------------------------
173// (void) trig_constant
174// Display the constant pi (3.141592653589793)
175// -------------------------------------------------------
176- (void) trig_constant: (double) trig_const
177{
178    current_value 	= trig_const;
179    trailing_digits 	= 0;
180    isNewDigit 		= YES;
181}
182
183// -------------------------------------------------------
184// (void) e
185// Display the constant e (2.718281828459045)
186// -------------------------------------------------------
187- (void)e
188{
189    current_value 	= M_E;
190    trailing_digits 	= 0;
191    isNewDigit 		= YES;
192}
193
194// -------------------------------------------------------
195// (void) clear
196// clear the displayField and reset several variables
197// -------------------------------------------------------
198- (void) clear
199{
200    current_value 	= 0.0;
201    previous_value 	= 0.0;
202    op_type 		= NO_OP;
203    trailing_digits 	= 0;
204    isNewDigit 	= YES;
205}
206
207// -------------------------------------------------------
208// (void)operation:(OpType)new_op_type
209// -------------------------------------------------------
210- (void)operation:(OpType)new_op_type
211{
212    if (op_type == NO_OP)
213    {
214        previous_value 	= current_value;
215        isNewDigit 	= YES;
216        op_type 	= new_op_type;
217        trailing_digits = 0;
218    }
219    else
220    {
221        // cascading operations
222        [self enter]; // calculate previous value, first
223        previous_value = current_value;
224        isNewDigit = YES;
225        op_type = new_op_type;
226        trailing_digits = 0;
227    }
228}
229
230// -------------------------------------------------------
231// (void)enter
232// For binary operators (+, -, x, /, etc.), calculate
233// the value and place into current_value
234// -------------------------------------------------------
235- (void)enter
236{
237    switch (op_type)
238    {
239        case NO_OP:
240            break;
241        case ADD_OP:
242            current_value = previous_value + current_value;
243            break;
244        case SUBTRACT_OP:
245            current_value = previous_value - current_value;
246            break;
247        case MULTIPLY_OP:
248            current_value = previous_value * current_value;
249            break;
250        case DIVIDE_OP:
251            if (current_value != 0.0)
252            {
253                current_value = previous_value / current_value;
254            }
255            break;
256        case EXPONENT_OP: // x^y
257            current_value = pow(previous_value, current_value);
258            break;
259        case XROOT_OP: // y�x
260            current_value = pow(previous_value, 1/current_value);
261            break;
262        case MOD_OP:
263            current_value = (int)previous_value % (int)current_value;
264            break;
265        case EE_OP:
266            current_value = previous_value * pow(10, current_value);
267            break;
268        case NPR_OP: // n!/(n-r)!
269            current_value = [self factorial:previous_value] / [self factorial:(previous_value - current_value)];
270            break;
271        case NCR_OP: // n!/(r! * (n-r)!)
272            current_value = [self factorial:previous_value] / ([self factorial:current_value] * [self factorial:(previous_value - current_value)]);
273            break;
274    }
275    previous_value 	= 0.0;
276    op_type 		= NO_OP;
277    trailing_digits 	= 0;
278    isNewDigit 		= YES;
279}
280
281// =====================================================================================
282// ALGEBRAIC FUNCTIONS
283// =====================================================================================
284
285// -------------------------------------------------------
286// (void) reverse_sign
287// -------------------------------------------------------
288- (void) reverse_sign
289{
290    current_value = - current_value;
291}
292
293// -------------------------------------------------------
294// (void)percentage
295// -------------------------------------------------------
296- (void)percentage
297{
298    current_value = current_value * 0.01;
299    isNewDigit 	  = YES;
300    trailing_digits = 0;
301}
302
303// -------------------------------------------------------
304// (void) squared
305// -------------------------------------------------------
306- (void) squared
307{
308    current_value = pow(current_value, 2);
309    isNewDigit    = YES;
310}
311
312// -------------------------------------------------------
313// (void) cubed
314// -------------------------------------------------------
315- (void) cubed
316{
317    current_value = pow(current_value, 3);
318    isNewDigit    = true;
319}
320
321// -------------------------------------------------------
322// (void) square_root
323// -------------------------------------------------------
324- (void) square_root
325{
326    if (current_value >= 0.0)
327    {
328        current_value = sqrt(current_value);
329    }
330
331    isNewDigit = YES;
332}
333
334// -------------------------------------------------------
335// (void) cubed_root
336// -------------------------------------------------------
337- (void)cubed_root
338{
339    //if (current_value >= 0.0)
340    //{
341        current_value = pow(current_value, 0.3333333333333333);
342    //}
343
344    isNewDigit = YES;
345}
346
347// -------------------------------------------------------
348// (void) ln
349// natural log
350// -------------------------------------------------------
351- (void)ln
352{
353    if (current_value > 0.0)
354    {
355        current_value = log(current_value);
356    }
357
358    isNewDigit = YES;
359}
360
361// -------------------------------------------------------
362// (void) cubed_root
363// logarithm base 10
364// -------------------------------------------------------
365- (void)logarithm
366{
367    if (current_value > 0.0)
368    {
369        current_value = log10(current_value);
370    }
371
372    isNewDigit = YES;
373}
374
375// -------------------------------------------------------
376// (void) factorial
377// This new function replaces the old factorial function
378// with a gamma function.  For more information, read the
379// lgamma man page or
380// http://www.gnu.org/software/libc/manual/html_node/Special-Functions.html
381// Version: 8. March 2004 23:40
382// -------------------------------------------------------
383- (void) factorial
384{
385    double lg;
386
387    // 170.5 seems to be the max value which EdenMath can handle
388    if (current_value < 170.5)
389    {
390        lg = lgamma(current_value+1.0);
391        current_value = signgam*exp(lg); /* signgam is a predefined variable */
392    }
393
394    trailing_digits = 0; // this allows for more precise decimal precision
395    isNewDigit = YES;
396
397}
398
399// -------------------------------------------------------
400// (double) factorial: (double) n
401// This is required for the permutations and combinations
402// calls.
403// Version: 9. March 2004 23:48
404// -------------------------------------------------------
405- (double) factorial: (double) n
406{
407    double lg;
408
409    // 170.5 seems to be the max value which EdenMath can handle
410    if (n < 170.5)
411    {
412        lg = lgamma(n+1.0);
413        n = signgam*exp(lg);
414    }
415
416    return (n);
417
418}
419
420// -------------------------------------------------------
421// (void) powerE
422// e^x
423// M_E is a constant hidden somewhere in the included
424// libraries
425// -------------------------------------------------------
426- (void) powerE
427{
428    current_value = pow(M_E, current_value);
429    isNewDigit    = YES;
430}
431
432// -------------------------------------------------------
433// (void) 10^x
434// -------------------------------------------------------
435- (void) power10
436{
437    current_value = pow(10, current_value);
438    isNewDigit 	  = YES;
439}
440
441// -------------------------------------------------------
442// (void) inverse
443// -------------------------------------------------------
444- (void)inverse
445{
446    if (current_value != 0.0)
447    {
448        current_value = 1/current_value;
449    }
450
451    isNewDigit = YES;
452}
453
454// =====================================================================================
455// TRIGOMETRIC FUNCTIONS
456// =====================================================================================
457
458// -------------------------------------------------------
459// (void) setAngleType:(AngleType)aType
460// Modify the type of angles using degrees, radians, or
461// gradients.  EM 1.1.1 reduced this code down to one
462// line, eliminating multiple IF-ELSE statements.
463// -------------------------------------------------------
464// Version: 31. May 2003
465// -------------------------------------------------------
466- (void)setAngleType:(AngleType)aType
467{
468    angle_type = aType;
469}
470
471// -------------------------------------------------------
472// (double)deg_to_rad:(double)degrees
473// Convert from degrees to radians
474// -------------------------------------------------------
475- (double)deg_to_rad:(double)degrees
476{
477    double radians = 0.0;
478    radians = degrees * M_PI / 180;
479
480    return radians;
481}
482
483// -------------------------------------------------------
484// (double)rad_to_deg:(double)radians
485// Convert from radians to degrees
486// -------------------------------------------------------
487// Created: 31. May 2003
488// Version: 31. May 2003
489// -------------------------------------------------------
490- (double)rad_to_deg:(double)radians
491{
492    double degrees = 0.0;
493    degrees = radians * 180 / M_PI;
494
495    return degrees;
496}
497
498// -------------------------------------------------------
499// (double)grad_to_rad:(double)gradients
500// Convert from gradients to radians
501// http://www.onlineconversion.com/angles.htm
502// 1 gradient = 0.015707963267948966192 radians
503// 1 gradient = 0.9 degrees
504// Created higher precision for the conversion so
505// Tan(50g) would equal 1.  Otherwise, if the conversion
506// isn't precise enough, it comes out to be 1.000003672.
507// -------------------------------------------------------
508// Version: 31. May 2003
509// -------------------------------------------------------
510- (double)grad_to_rad:(double)gradients
511{
512    double radians = 0.0;
513    radians = gradients * 0.015707963267948966192;
514
515    return radians;
516}
517
518// -------------------------------------------------------
519// (double)rad_to_grad:(double)radians
520// Convert from radians to gradients
521// http://www.onlineconversion.com/angles.htm
522// 1 gradient = 0.015707963267948966192 radians
523// 1 gradient = 0.9 degrees
524// -------------------------------------------------------
525// Created: 31. May 2003
526// Version: 31. May 2003
527// -------------------------------------------------------
528- (double)rad_to_grad:(double)radians
529{
530    double gradients = 0.0;
531    gradients = radians / 0.015707963267948966192;
532
533    return gradients;
534}
535
536// -------------------------------------------------------
537// (void) sine
538// -------------------------------------------------------
539- (void)sine
540{
541    if (angle_type == DEGREE)
542    {
543        current_value = [self deg_to_rad:current_value];
544    }
545    else if (angle_type == GRADIENT)
546    {
547        current_value = [self grad_to_rad:current_value];
548    }
549
550    current_value = sin(current_value);
551    isNewDigit 	  = YES;
552}
553
554// -------------------------------------------------------
555// (void) cosine
556// -------------------------------------------------------
557- (void)cosine
558{
559    if (angle_type == DEGREE)
560    {
561        current_value = [self deg_to_rad:current_value];
562    }
563    else if (angle_type == GRADIENT)
564    {
565        current_value = [self grad_to_rad:current_value];
566    }
567
568    current_value = cos(current_value);
569    isNewDigit 	  = YES;
570}
571
572// -------------------------------------------------------
573// (void) tangent
574// -------------------------------------------------------
575- (void)tangent
576{
577    if (angle_type == DEGREE)
578    {
579        current_value = [self deg_to_rad:current_value];
580    }
581    else if (angle_type == GRADIENT)
582    {
583        current_value = [self grad_to_rad:current_value];
584    }
585
586    if ( ( current_value == M_PI/2) || (current_value == 3 * M_PI / 2) ||
587         ( current_value == - M_PI/2) || (current_value == -3 * M_PI / 2) )
588    {
589        NSBeep();
590        NSRunAlertPanel(@"Warning", @"Tan cannot calculate values of �/2 or 3�/2",
591                        @"OK", nil, nil);
592    }
593    else // otherwise, tan will still be calculated on �/2 or 3�/2, which is wrong.
594    {
595        current_value = tan(current_value);
596    }
597
598    isNewDigit    = YES;
599}
600
601// -------------------------------------------------------
602// (void) arcsine
603// -------------------------------------------------------
604// Version: 31. May 2003
605// -------------------------------------------------------
606- (void)arcsine
607{
608    current_value = asin(current_value);
609    isNewDigit 	 = YES;
610
611    if (angle_type == DEGREE)
612    {
613        current_value = [self rad_to_deg:current_value];
614    }
615    else if (angle_type == GRADIENT)
616    {
617        current_value = [self rad_to_grad:current_value];
618    }
619}
620
621// -------------------------------------------------------
622// (void) arccosine
623// -------------------------------------------------------
624// Version: 31. May 2003
625// -------------------------------------------------------
626- (void)arccosine
627{
628    current_value = acos(current_value);
629    isNewDigit 	  = YES;
630
631    if (angle_type == DEGREE)
632    {
633        current_value = [self rad_to_deg:current_value];
634    }
635    else if (angle_type == GRADIENT)
636    {
637        current_value = [self rad_to_grad:current_value];
638    }
639}
640
641// -------------------------------------------------------
642// (void) arctangent
643// -------------------------------------------------------
644// Version: 31. May 2003
645// -------------------------------------------------------
646- (void)arctangent
647{
648    current_value = atan(current_value);
649    isNewDigit 	  = YES;
650
651    if (angle_type == DEGREE)
652    {
653        current_value = [self rad_to_deg:current_value];
654    }
655    else if (angle_type == GRADIENT)
656    {
657        current_value = [self rad_to_grad:current_value];
658    }
659}
660
661// =====================================================================================
662// PROBABILITY FUNCTIONS
663// The Probability and Combination functions are in the enter function since they
664// act as binary operators
665// =====================================================================================
666
667// -------------------------------------------------------
668// (void) generate_random_num
669// -------------------------------------------------------
670- (double) generate_random_num
671{
672    static int seeded = 0;
673    double value = 0.0;
674
675    if (seeded == 0)
676    {
677        srand((unsigned)time((time_t *)NULL));
678        seeded = 1;
679    }
680
681    value = rand();
682
683    return value;
684}
685
686// -------------------------------------------------------
687// (void) random_num
688// -------------------------------------------------------
689- (void) random_num
690{
691    current_value = [self generate_random_num];
692    isNewDigit 	 = YES;
693}
694
695@end
696