summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMoshe Piekarski <dev.rockbox@melachim.net>2021-05-12 23:11:54 -0400
committerAidan MacDonald <amachronic@protonmail.com>2021-06-16 19:50:14 +0000
commit9ccae0421a356c79d3d6cdbdbd9798a60f8d1ed7 (patch)
tree37ff6458b0c5b1a1dee2da869c57fbcebc70bd6f /apps
parenta3f2b64a467c10307ba32ac5e7cd06f5fc27b47f (diff)
Implement x^y in calculator
Change-Id: I868b703131675876bd91198b8a53a921152aecba
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/calculator.c176
1 files changed, 173 insertions, 3 deletions
diff --git a/apps/plugins/calculator.c b/apps/plugins/calculator.c
index ebf7098d65..45d3643a70 100644
--- a/apps/plugins/calculator.c
+++ b/apps/plugins/calculator.c
@@ -720,6 +720,8 @@ static void doMultiple(double* operandOne, int* powerOne,
double operandTwo, int powerTwo);
static void doAdd (double* operandOne, int* powerOne,
double operandTwo, int powerTwo);
+static void doExponent(double* operandOne, int* powerOne,
+ double operandTwo, int powerTwo);
static void printResult(void);
static void formatResult(void);
static void oneOperand(void);
@@ -727,6 +729,75 @@ static void oneOperand(void);
static void drawLines(void);
static void drawButtons(int group);
+double strtod(const char *nptr, char **endptr);
+long long atoll(const char *nptr);
+
+/* -----------------------------------------------------------------------
+Standard library function
+----------------------------------------------------------------------- */
+double strtod(const char *nptr, char **endptr)
+{
+ double out;
+ long mantissa;
+ int length=0, end=0;
+ mantissa=atoll(nptr);
+ while(!end)
+ {
+ switch(*nptr)
+ {
+ case '\0':
+ end=1;
+ break;
+ case ',':
+ case '.':
+ case '\'':
+ end=1;
+ default:
+ nptr++;
+ }
+ }
+ out=atoll(nptr);
+ while( (*nptr == '0')||(*nptr == '1')||(*nptr == '2')||(*nptr == '3')||(*nptr == '4')||
+ (*nptr == '5')||(*nptr == '6')||(*nptr == '7')||(*nptr == '8')||(*nptr == '9') )
+ {
+ nptr++;
+ length++;
+ }
+ for(;length;length--)
+ out /= 10;
+ out += mantissa;
+ if(endptr != NULL)
+ *endptr=(char *) nptr;
+ return out;
+}
+
+// WARNING Unsafe: Use strtoll instead
+long long atoll(const char *nptr)
+{
+ long long result=0;
+ char negative=0;
+ while( (*nptr == ' ') || (*nptr == '\f') || (*nptr == '\n')||
+ (*nptr == '\r') || (*nptr == '\t') || (*nptr == '\v') )
+ nptr++;
+ if(*nptr == '+')
+ nptr++;
+ if(*nptr == '-')
+ {
+ negative++;
+ nptr++;
+ }
+ while (*nptr)
+ {
+ if( (*nptr < '0') || (*nptr > '9') )
+ break;
+ result *=10;
+ result+= (*(nptr++) -'0');
+ }
+ if(negative)
+ result = 0 - result;
+ return result;
+}
+
/* -----------------------------------------------------------------------
Handy functions
----------------------------------------------------------------------- */
@@ -1049,6 +1120,91 @@ static void doMultiple(double* operandOne, int* powerOne,
}
/* -----------------------------------------------------------------------
+exponentiate in scientific number format
+----------------------------------------------------------------------- */
+static void doExponent(double* operandOne, int* powerOne,
+ double operandTwo, int powerTwo)
+{
+ char negative=0;
+ char *lastDigit;
+ char negativeBuffer[25];
+ if (*operandOne == 0)
+ {
+ if (operandTwo == 0)
+ {
+ calStatus=cal_error; // result is undefined
+ }
+ else{
+ *powerOne = 0;
+ *operandOne = 0;
+ }
+ return;
+ }
+ if (operandTwo == 0)
+ {
+ *powerOne = 1;
+ *operandOne = 0.1;
+ return;
+ }
+ if (operandTwo < 0)
+ {
+ negative+=2;
+ operandTwo= ABS(operandTwo);
+ }
+ if (*operandOne < 0)
+ {
+#if MEMORYSIZE < 8
+ calStatus=cal_error;
+ return;
+#else
+ if(powerTwo < 0)
+ {
+ calStatus=cal_error; // result is imaginary
+ return;
+ }
+
+ /*Truncate operandTwo to three places past the radix
+ in order to eliminate floating point artifacts
+ (function should set error if truncating a non-integer) */
+ rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo+3, operandTwo);
+ operandTwo = strtod(negativeBuffer, NULL);
+
+ /*Truncate operandTwo to powerTwo digits by way of string
+ in order to confirm operandTwo *10^powerTwo is an integer*/
+ rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo, operandTwo);
+
+ if(strtod(negativeBuffer, &lastDigit) != operandTwo)
+ {
+ calStatus=cal_error; // result is imaginary
+ return;
+ }
+ if(rb->atoi(lastDigit-1) % 2)
+ negative++;
+#endif
+ }
+ (*operandOne) = myLn(ABS(*operandOne)) + (double) (*powerOne) * 2.302585092994046;
+ (*powerOne) = 0;
+ doMultiple(operandOne, powerOne, ABS(operandTwo), powerTwo);
+ while(*powerOne)
+ {
+ if(*powerOne > 0)
+ {
+ (*operandOne) *= 10;
+ (*powerOne) --;
+ }
+ else{
+ (*operandOne) /= 10;
+ (*powerOne) ++;
+ }
+ }
+ (*operandOne) = myExp(*operandOne);
+ if(negative & 2)
+ (*operandOne) = 1/(*operandOne);
+ if(negative & 1)
+ *operandOne = -(*operandOne);
+}
+
+/* -----------------------------------------------------------------------
Handles all one operand calculations
----------------------------------------------------------------------- */
static void oneOperand(void)
@@ -1192,6 +1348,9 @@ static void twoOperands(void)
else
calStatus = cal_error;
break;
+ case '^':
+ doExponent(&operand, &operandPower, result, power);
+ break;
default: /* ' ' */
switchOperands(); /* counter switchOperands() below */
break;
@@ -1684,7 +1843,9 @@ static void basicButtonsProcess(void){
#ifdef CALCULATOR_OPERATORS
case_cycle_operators: /* F2 shortkey entrance */
#endif
- calStatus = cal_normal;
+ if (calStatus == cal_typing ||
+ calStatus == cal_dotted)
+ calStatus = cal_normal;
formatResult();
operand = result;
operandPower = power;
@@ -1740,8 +1901,17 @@ static void sciButtonsProcess(void){
break;
case sci_xy:
- /*Not implemented yet
- Maybe it could use x^y = exp(y*ln(x))*/
+ if(!operInputted) {twoOperands(); operInputted = true;}
+ oper = '^';
+#ifdef CALCULATOR_OPERATORS
+ case_cycle_operators: /* F2 shortkey entrance */
+#endif
+ if (calStatus == cal_typing ||
+ calStatus == cal_dotted)
+ calStatus = cal_normal;
+ formatResult();
+ operand = result;
+ operandPower = power;
break;
case sci_sci: