diff options
author | Moshe Piekarski <dev.rockbox@melachim.net> | 2021-05-12 23:11:54 -0400 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-06-16 19:50:14 +0000 |
commit | 9ccae0421a356c79d3d6cdbdbd9798a60f8d1ed7 (patch) | |
tree | 37ff6458b0c5b1a1dee2da869c57fbcebc70bd6f | |
parent | a3f2b64a467c10307ba32ac5e7cd06f5fc27b47f (diff) | |
download | rockbox-9ccae0421a356c79d3d6cdbdbd9798a60f8d1ed7.tar.gz rockbox-9ccae0421a356c79d3d6cdbdbd9798a60f8d1ed7.zip |
Implement x^y in calculator
Change-Id: I868b703131675876bd91198b8a53a921152aecba
-rw-r--r-- | apps/plugins/calculator.c | 176 |
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, | |||
720 | double operandTwo, int powerTwo); | 720 | double operandTwo, int powerTwo); |
721 | static void doAdd (double* operandOne, int* powerOne, | 721 | static void doAdd (double* operandOne, int* powerOne, |
722 | double operandTwo, int powerTwo); | 722 | double operandTwo, int powerTwo); |
723 | static void doExponent(double* operandOne, int* powerOne, | ||
724 | double operandTwo, int powerTwo); | ||
723 | static void printResult(void); | 725 | static void printResult(void); |
724 | static void formatResult(void); | 726 | static void formatResult(void); |
725 | static void oneOperand(void); | 727 | static void oneOperand(void); |
@@ -727,6 +729,75 @@ static void oneOperand(void); | |||
727 | static void drawLines(void); | 729 | static void drawLines(void); |
728 | static void drawButtons(int group); | 730 | static void drawButtons(int group); |
729 | 731 | ||
732 | double strtod(const char *nptr, char **endptr); | ||
733 | long long atoll(const char *nptr); | ||
734 | |||
735 | /* ----------------------------------------------------------------------- | ||
736 | Standard library function | ||
737 | ----------------------------------------------------------------------- */ | ||
738 | double strtod(const char *nptr, char **endptr) | ||
739 | { | ||
740 | double out; | ||
741 | long mantissa; | ||
742 | int length=0, end=0; | ||
743 | mantissa=atoll(nptr); | ||
744 | while(!end) | ||
745 | { | ||
746 | switch(*nptr) | ||
747 | { | ||
748 | case '\0': | ||
749 | end=1; | ||
750 | break; | ||
751 | case ',': | ||
752 | case '.': | ||
753 | case '\'': | ||
754 | end=1; | ||
755 | default: | ||
756 | nptr++; | ||
757 | } | ||
758 | } | ||
759 | out=atoll(nptr); | ||
760 | while( (*nptr == '0')||(*nptr == '1')||(*nptr == '2')||(*nptr == '3')||(*nptr == '4')|| | ||
761 | (*nptr == '5')||(*nptr == '6')||(*nptr == '7')||(*nptr == '8')||(*nptr == '9') ) | ||
762 | { | ||
763 | nptr++; | ||
764 | length++; | ||
765 | } | ||
766 | for(;length;length--) | ||
767 | out /= 10; | ||
768 | out += mantissa; | ||
769 | if(endptr != NULL) | ||
770 | *endptr=(char *) nptr; | ||
771 | return out; | ||
772 | } | ||
773 | |||
774 | // WARNING Unsafe: Use strtoll instead | ||
775 | long long atoll(const char *nptr) | ||
776 | { | ||
777 | long long result=0; | ||
778 | char negative=0; | ||
779 | while( (*nptr == ' ') || (*nptr == '\f') || (*nptr == '\n')|| | ||
780 | (*nptr == '\r') || (*nptr == '\t') || (*nptr == '\v') ) | ||
781 | nptr++; | ||
782 | if(*nptr == '+') | ||
783 | nptr++; | ||
784 | if(*nptr == '-') | ||
785 | { | ||
786 | negative++; | ||
787 | nptr++; | ||
788 | } | ||
789 | while (*nptr) | ||
790 | { | ||
791 | if( (*nptr < '0') || (*nptr > '9') ) | ||
792 | break; | ||
793 | result *=10; | ||
794 | result+= (*(nptr++) -'0'); | ||
795 | } | ||
796 | if(negative) | ||
797 | result = 0 - result; | ||
798 | return result; | ||
799 | } | ||
800 | |||
730 | /* ----------------------------------------------------------------------- | 801 | /* ----------------------------------------------------------------------- |
731 | Handy functions | 802 | Handy functions |
732 | ----------------------------------------------------------------------- */ | 803 | ----------------------------------------------------------------------- */ |
@@ -1049,6 +1120,91 @@ static void doMultiple(double* operandOne, int* powerOne, | |||
1049 | } | 1120 | } |
1050 | 1121 | ||
1051 | /* ----------------------------------------------------------------------- | 1122 | /* ----------------------------------------------------------------------- |
1123 | exponentiate in scientific number format | ||
1124 | ----------------------------------------------------------------------- */ | ||
1125 | static void doExponent(double* operandOne, int* powerOne, | ||
1126 | double operandTwo, int powerTwo) | ||
1127 | { | ||
1128 | char negative=0; | ||
1129 | char *lastDigit; | ||
1130 | char negativeBuffer[25]; | ||
1131 | if (*operandOne == 0) | ||
1132 | { | ||
1133 | if (operandTwo == 0) | ||
1134 | { | ||
1135 | calStatus=cal_error; // result is undefined | ||
1136 | } | ||
1137 | else{ | ||
1138 | *powerOne = 0; | ||
1139 | *operandOne = 0; | ||
1140 | } | ||
1141 | return; | ||
1142 | } | ||
1143 | if (operandTwo == 0) | ||
1144 | { | ||
1145 | *powerOne = 1; | ||
1146 | *operandOne = 0.1; | ||
1147 | return; | ||
1148 | } | ||
1149 | if (operandTwo < 0) | ||
1150 | { | ||
1151 | negative+=2; | ||
1152 | operandTwo= ABS(operandTwo); | ||
1153 | } | ||
1154 | if (*operandOne < 0) | ||
1155 | { | ||
1156 | #if MEMORYSIZE < 8 | ||
1157 | calStatus=cal_error; | ||
1158 | return; | ||
1159 | #else | ||
1160 | if(powerTwo < 0) | ||
1161 | { | ||
1162 | calStatus=cal_error; // result is imaginary | ||
1163 | return; | ||
1164 | } | ||
1165 | |||
1166 | /*Truncate operandTwo to three places past the radix | ||
1167 | in order to eliminate floating point artifacts | ||
1168 | (function should set error if truncating a non-integer) */ | ||
1169 | rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo+3, operandTwo); | ||
1170 | operandTwo = strtod(negativeBuffer, NULL); | ||
1171 | |||
1172 | /*Truncate operandTwo to powerTwo digits by way of string | ||
1173 | in order to confirm operandTwo *10^powerTwo is an integer*/ | ||
1174 | rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo, operandTwo); | ||
1175 | |||
1176 | if(strtod(negativeBuffer, &lastDigit) != operandTwo) | ||
1177 | { | ||
1178 | calStatus=cal_error; // result is imaginary | ||
1179 | return; | ||
1180 | } | ||
1181 | if(rb->atoi(lastDigit-1) % 2) | ||
1182 | negative++; | ||
1183 | #endif | ||
1184 | } | ||
1185 | (*operandOne) = myLn(ABS(*operandOne)) + (double) (*powerOne) * 2.302585092994046; | ||
1186 | (*powerOne) = 0; | ||
1187 | doMultiple(operandOne, powerOne, ABS(operandTwo), powerTwo); | ||
1188 | while(*powerOne) | ||
1189 | { | ||
1190 | if(*powerOne > 0) | ||
1191 | { | ||
1192 | (*operandOne) *= 10; | ||
1193 | (*powerOne) --; | ||
1194 | } | ||
1195 | else{ | ||
1196 | (*operandOne) /= 10; | ||
1197 | (*powerOne) ++; | ||
1198 | } | ||
1199 | } | ||
1200 | (*operandOne) = myExp(*operandOne); | ||
1201 | if(negative & 2) | ||
1202 | (*operandOne) = 1/(*operandOne); | ||
1203 | if(negative & 1) | ||
1204 | *operandOne = -(*operandOne); | ||
1205 | } | ||
1206 | |||
1207 | /* ----------------------------------------------------------------------- | ||
1052 | Handles all one operand calculations | 1208 | Handles all one operand calculations |
1053 | ----------------------------------------------------------------------- */ | 1209 | ----------------------------------------------------------------------- */ |
1054 | static void oneOperand(void) | 1210 | static void oneOperand(void) |
@@ -1192,6 +1348,9 @@ static void twoOperands(void) | |||
1192 | else | 1348 | else |
1193 | calStatus = cal_error; | 1349 | calStatus = cal_error; |
1194 | break; | 1350 | break; |
1351 | case '^': | ||
1352 | doExponent(&operand, &operandPower, result, power); | ||
1353 | break; | ||
1195 | default: /* ' ' */ | 1354 | default: /* ' ' */ |
1196 | switchOperands(); /* counter switchOperands() below */ | 1355 | switchOperands(); /* counter switchOperands() below */ |
1197 | break; | 1356 | break; |
@@ -1684,7 +1843,9 @@ static void basicButtonsProcess(void){ | |||
1684 | #ifdef CALCULATOR_OPERATORS | 1843 | #ifdef CALCULATOR_OPERATORS |
1685 | case_cycle_operators: /* F2 shortkey entrance */ | 1844 | case_cycle_operators: /* F2 shortkey entrance */ |
1686 | #endif | 1845 | #endif |
1687 | calStatus = cal_normal; | 1846 | if (calStatus == cal_typing || |
1847 | calStatus == cal_dotted) | ||
1848 | calStatus = cal_normal; | ||
1688 | formatResult(); | 1849 | formatResult(); |
1689 | operand = result; | 1850 | operand = result; |
1690 | operandPower = power; | 1851 | operandPower = power; |
@@ -1740,8 +1901,17 @@ static void sciButtonsProcess(void){ | |||
1740 | break; | 1901 | break; |
1741 | 1902 | ||
1742 | case sci_xy: | 1903 | case sci_xy: |
1743 | /*Not implemented yet | 1904 | if(!operInputted) {twoOperands(); operInputted = true;} |
1744 | Maybe it could use x^y = exp(y*ln(x))*/ | 1905 | oper = '^'; |
1906 | #ifdef CALCULATOR_OPERATORS | ||
1907 | case_cycle_operators: /* F2 shortkey entrance */ | ||
1908 | #endif | ||
1909 | if (calStatus == cal_typing || | ||
1910 | calStatus == cal_dotted) | ||
1911 | calStatus = cal_normal; | ||
1912 | formatResult(); | ||
1913 | operand = result; | ||
1914 | operandPower = power; | ||
1745 | break; | 1915 | break; |
1746 | 1916 | ||
1747 | case sci_sci: | 1917 | case sci_sci: |