[CALC] Improve multi-precision support, and powers/roots. CORE-8486

- Added support for average of squares and mean of squares into statistical functions.
- pop() and push() functions in RPN engines now work with nodes instead of stack units.
- Moved the POW and SQR operations near the operators.
CORE-12766

- Fix number of digits for IEEE-754 constants.
- Show all available digits in exp notation.
CORE-14871

- Update help correspondingly.
This commit is contained in:
Carlo-Bramini 2018-08-06 09:54:21 +02:00 committed by Hermès Bélusca-Maïto
parent 28f493624a
commit 295eaf4e32
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
10 changed files with 360 additions and 142 deletions

View file

@ -11,6 +11,7 @@
#ifndef DISABLE_HTMLHELP_SUPPORT #ifndef DISABLE_HTMLHELP_SUPPORT
#include <htmlhelp.h> #include <htmlhelp.h>
#endif #endif
#include <limits.h>
/* Messages reserved for the main dialog */ /* Messages reserved for the main dialog */
#define WM_CLOSE_STATS (WM_APP+1) #define WM_CLOSE_STATS (WM_APP+1)
@ -21,8 +22,9 @@
#define WM_HANDLE_FROM (WM_APP+6) #define WM_HANDLE_FROM (WM_APP+6)
#define WM_HANDLE_TO (WM_APP+7) #define WM_HANDLE_TO (WM_APP+7)
/* GNU MULTI-PRECISION LIBRARY support */
#ifdef ENABLE_MULTI_PRECISION #ifdef ENABLE_MULTI_PRECISION
#include <mpfr.h> #include "mpfr.h"
#ifndef MPFR_DEFAULT_RND #ifndef MPFR_DEFAULT_RND
#define MPFR_DEFAULT_RND mpfr_get_default_rounding_mode () #define MPFR_DEFAULT_RND mpfr_get_default_rounding_mode ()
@ -155,11 +157,11 @@ typedef struct {
extern calc_t calc; extern calc_t calc;
#define CALC_E 2.7182818284590452354 /* IEEE constants */
#define CALC_E 2.718281828459045235360
#define CALC_PI_2 1.57079632679489661923 #define CALC_PI_2 1.570796326794896619231
#define CALC_PI 3.14159265358979323846 #define CALC_PI 3.141592653589793238462
#define CALC_3_PI_2 4.71238898038468985769 #define CALC_3_PI_2 4.712388980384689857694
#define CALC_2_PI 6.283185307179586476925 #define CALC_2_PI 6.283185307179586476925
#define MODIFIER_INV 0x01 #define MODIFIER_INV 0x01
@ -167,14 +169,9 @@ extern calc_t calc;
#define NO_CHAIN 0x04 #define NO_CHAIN 0x04
void apply_int_mask(calc_number_t *a); void apply_int_mask(calc_number_t *a);
#ifdef ENABLE_MULTI_PRECISION #ifndef ENABLE_MULTI_PRECISION
void validate_rad2angle(calc_number_t *c);
void validate_angle2rad(calc_number_t *c);
#else
__int64 logic_dbl2int(calc_number_t *a); __int64 logic_dbl2int(calc_number_t *a);
double logic_int2dbl(calc_number_t *a); double logic_int2dbl(calc_number_t *a);
double validate_rad2angle(double a);
double validate_angle2rad(calc_number_t *c);
#endif #endif
void rpn_sin(calc_number_t *c); void rpn_sin(calc_number_t *c);
void rpn_cos(calc_number_t *c); void rpn_cos(calc_number_t *c);
@ -206,7 +203,9 @@ void rpn_exp10(calc_number_t *c);
void rpn_ln(calc_number_t *c); void rpn_ln(calc_number_t *c);
void rpn_log(calc_number_t *c); void rpn_log(calc_number_t *c);
void rpn_ave(calc_number_t *c); void rpn_ave(calc_number_t *c);
void rpn_ave2(calc_number_t *c);
void rpn_sum(calc_number_t *c); void rpn_sum(calc_number_t *c);
void rpn_sum2(calc_number_t *c);
void rpn_s(calc_number_t *c); void rpn_s(calc_number_t *c);
void rpn_s_m1(calc_number_t *c); void rpn_s_m1(calc_number_t *c);
void rpn_dms2dec(calc_number_t *c); void rpn_dms2dec(calc_number_t *c);
@ -217,10 +216,14 @@ int rpn_is_zero(calc_number_t *c);
void rpn_alloc(calc_number_t *c); void rpn_alloc(calc_number_t *c);
void rpn_free(calc_number_t *c); void rpn_free(calc_number_t *c);
//
void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base); void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base);
void convert_text2number_2(calc_number_t *a); void convert_text2number_2(calc_number_t *a);
void convert_real_integer(unsigned int base); void convert_real_integer(unsigned int base);
//
INT_PTR CALLBACK AboutDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp); INT_PTR CALLBACK AboutDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
void ConvExecute(HWND hWnd); void ConvExecute(HWND hWnd);

View file

@ -1,6 +1,27 @@
/*
* ReactOS Calc (Math functions, IEEE-754 engine)
*
* Copyright 2007-2017, Carlo Bramini
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "calc.h" #include "calc.h"
#include <limits.h> static double validate_rad2angle(double a);
static double validate_angle2rad(calc_number_t *c);
void apply_int_mask(calc_number_t *r) void apply_int_mask(calc_number_t *r)
{ {
@ -47,7 +68,7 @@ double atanh(double x)
return log((1.0+x)/(1.0-x))/2.0; return log((1.0+x)/(1.0-x))/2.0;
} }
double validate_rad2angle(double a) static double validate_rad2angle(double a)
{ {
switch (calc.degr) { switch (calc.degr) {
case IDC_RADIO_DEG: case IDC_RADIO_DEG:
@ -62,7 +83,7 @@ double validate_rad2angle(double a)
return a; return a;
} }
double validate_angle2rad(calc_number_t *c) static double validate_angle2rad(calc_number_t *c)
{ {
switch (calc.degr) { switch (calc.degr) {
case IDC_RADIO_DEG: case IDC_RADIO_DEG:
@ -250,6 +271,7 @@ __int64 logic_dbl2int(calc_number_t *a)
} }
return (__int64)int_part; return (__int64)int_part;
} }
double logic_int2dbl(calc_number_t *a) double logic_int2dbl(calc_number_t *a)
{ {
return (double)a->i; return (double)a->i;
@ -315,9 +337,9 @@ static unsigned __int64 sqrti(unsigned __int64 number)
unsigned __int64 n, n1; unsigned __int64 n, n1;
#ifdef __GNUC__ #ifdef __GNUC__
if (number == 0xffffffffffffffffLL) if (number == 0xffffffffffffffffULL)
#else #else
if (number == 0xffffffffffffffff) if (number == 0xffffffffffffffffUI64)
#endif #endif
return 0xffffffff; return 0xffffffff;
@ -427,6 +449,21 @@ static double stat_sum(void)
return sum; return sum;
} }
static double stat_sum2(void)
{
double sum = 0;
statistic_t *p = calc.stat;
while (p != NULL) {
if (p->base == IDC_RADIO_DEC)
sum += p->num.f * p->num.f;
else
sum += (double)p->num.i * (double)p->num.i;
p = (statistic_t *)(p->next);
}
return sum;
}
void rpn_ave(calc_number_t *c) void rpn_ave(calc_number_t *c)
{ {
double ave = 0; double ave = 0;
@ -443,6 +480,22 @@ void rpn_ave(calc_number_t *c)
c->i = (__int64)ave; c->i = (__int64)ave;
} }
void rpn_ave2(calc_number_t *c)
{
double ave = 0;
int n;
ave = stat_sum2();
n = SendDlgItemMessage(calc.hStatWnd, IDC_LIST_STAT, LB_GETCOUNT, 0, 0);
if (n)
ave = ave / (double)n;
if (calc.base == IDC_RADIO_DEC)
c->f = ave;
else
c->i = (__int64)ave;
}
void rpn_sum(calc_number_t *c) void rpn_sum(calc_number_t *c)
{ {
double sum = stat_sum(); double sum = stat_sum();
@ -453,6 +506,16 @@ void rpn_sum(calc_number_t *c)
c->i = (__int64)sum; c->i = (__int64)sum;
} }
void rpn_sum2(calc_number_t *c)
{
double sum = stat_sum2();
if (calc.base == IDC_RADIO_DEC)
c->f = sum;
else
c->i = (__int64)sum;
}
static void rpn_s_ex(calc_number_t *c, int pop_type) static void rpn_s_ex(calc_number_t *c, int pop_type)
{ {
double ave = 0; double ave = 0;

View file

@ -1,5 +1,28 @@
/*
* ReactOS Calc (Math functions, GMP/MPFR engine)
*
* Copyright 2007-2017, Carlo Bramini
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "calc.h" #include "calc.h"
static void validate_rad2angle(calc_number_t *c);
static void validate_angle2rad(calc_number_t *c);
void apply_int_mask(calc_number_t *r) void apply_int_mask(calc_number_t *r)
{ {
mpz_t a, mask; mpz_t a, mask;
@ -28,7 +51,7 @@ void apply_int_mask(calc_number_t *r)
mpz_clear(mask); mpz_clear(mask);
} }
void validate_rad2angle(calc_number_t *r) static void validate_rad2angle(calc_number_t *r)
{ {
mpfr_t mult, divs; mpfr_t mult, divs;
@ -55,7 +78,7 @@ void validate_rad2angle(calc_number_t *r)
mpfr_clear(divs); mpfr_clear(divs);
} }
void validate_angle2rad(calc_number_t *r) static void validate_angle2rad(calc_number_t *r)
{ {
mpfr_t mult, divs; mpfr_t mult, divs;
@ -341,6 +364,21 @@ static void stat_sum(mpfr_t sum)
} }
} }
static void stat_sum2(mpfr_t sum)
{
statistic_t *p = calc.stat;
mpfr_t sqr;
mpfr_init(sqr);
mpfr_set_ui(sum, 0, MPFR_DEFAULT_RND);
while (p != NULL) {
mpfr_mul(sqr, p->num.mf, p->num.mf, MPFR_DEFAULT_RND);
mpfr_add(sum, sum, sqr, MPFR_DEFAULT_RND);
p = (statistic_t *)(p->next);
}
mpfr_clear(sqr);
}
void rpn_ave(calc_number_t *c) void rpn_ave(calc_number_t *c)
{ {
int n; int n;
@ -355,6 +393,20 @@ void rpn_ave(calc_number_t *c)
mpfr_trunc(c->mf, c->mf); mpfr_trunc(c->mf, c->mf);
} }
void rpn_ave2(calc_number_t *c)
{
int n;
stat_sum2(c->mf);
n = SendDlgItemMessage(calc.hStatWnd, IDC_LIST_STAT, LB_GETCOUNT, 0, 0);
if (n)
mpfr_div_ui(c->mf, c->mf, n, MPFR_DEFAULT_RND);
if (calc.base != IDC_RADIO_DEC)
mpfr_trunc(c->mf, c->mf);
}
void rpn_sum(calc_number_t *c) void rpn_sum(calc_number_t *c)
{ {
stat_sum(c->mf); stat_sum(c->mf);
@ -363,6 +415,14 @@ void rpn_sum(calc_number_t *c)
mpfr_trunc(c->mf, c->mf); mpfr_trunc(c->mf, c->mf);
} }
void rpn_sum2(calc_number_t *c)
{
stat_sum2(c->mf);
if (calc.base != IDC_RADIO_DEC)
mpfr_trunc(c->mf, c->mf);
}
static void rpn_s_ex(calc_number_t *c, int pop_type) static void rpn_s_ex(calc_number_t *c, int pop_type)
{ {
mpfr_t dev; mpfr_t dev;

View file

@ -204,10 +204,16 @@ It deletes all numbers currently stored into the list.
While the statistical window is shown, four additional buttons are enabled: While the statistical window is shown, four additional buttons are enabled:
[Ave] [Ave]
It calculates the arithmetic average of the numbers stored into the list. It calculates the arithmetic average of the numbers stored into the list.
[Ave] + [Inv]
It calculates the arithmetic average of the squares of the numbers stored into the list.
[Sum] [Sum]
It calculates the sum of all numbers stored into the list. It calculates the sum of all numbers stored into the list.
[Sum] + [Inv]
It calculates the sum of the squares of all numbers stored into the list.
[s] [s]
It calculates the population standard deviations of the numbers stored into the list. It calculates the population standard deviations with base 'n-1' of the numbers stored into the list.
[s] + [Inv]
It calculates the population standard deviations with base 'n' of the numbers stored into the list.
[Dat] [Dat]
It inserts the number shown into the output display into the list. It inserts the number shown into the output display into the list.
@ -483,10 +489,12 @@ Shortcut from keyboard: CTRL-S
Ave Ave
It calculates the arithmetic average of the numbers stored into the statistical box. It calculates the arithmetic average of the numbers stored into the statistical box.
When used with [Inv] modifier it calculates the average of squares.
Shortcut from keyboard: CTRL-A Shortcut from keyboard: CTRL-A
Sum Sum
It calculates the sum of the numbers stored into the statistical box. It calculates the sum of the numbers stored into the statistical box.
When used with [Inv] modifier it calculates the summation of squares.
Shortcut from keyboard: CTRL-T Shortcut from keyboard: CTRL-T
s s

View file

@ -101,6 +101,7 @@
#define IDC_COMBO_FROM 1091 #define IDC_COMBO_FROM 1091
#define IDC_COMBO_TO 1092 #define IDC_COMBO_TO 1092
#define IDC_BUTTON_RSH 1093 #define IDC_BUTTON_RSH 1093
#define IDC_BUTTON_XrY 1094
/* TYPES OF CONVERSIONS */ /* TYPES OF CONVERSIONS */
#define IDS_CONV_ANGLE 2000 #define IDS_CONV_ANGLE 2000

View file

@ -1,3 +1,23 @@
/*
* ReactOS Calc (RPN encoder/decoder for IEEE-754 engine)
*
* Copyright 2007-2017, Carlo Bramini
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "calc.h" #include "calc.h"
typedef struct { typedef struct {
@ -15,7 +35,7 @@ typedef struct {
} calc_operator_t; } calc_operator_t;
static stack_node_t *stack; static stack_node_t *stack;
static stack_node_t temp; static calc_node_t temp;
static BOOL percent_mode; static BOOL percent_mode;
static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b); static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
@ -67,14 +87,20 @@ static const calc_operator_t operator_list[] = {
{ 7, rpn_sqr_f, NULL, NULL, }, // RPN_OPERATOR_SQR { 7, rpn_sqr_f, NULL, NULL, }, // RPN_OPERATOR_SQR
}; };
static stack_node_t *pop(void) static calc_node_t *pop(void)
{ {
void *next;
if (stack == NULL) if (stack == NULL)
return NULL; return NULL;
temp = *stack; /* copy the node */
temp = stack->node;
next = stack->next;
/* free the node */
free(stack); free(stack);
stack = temp.next; stack = next;
return &temp; return &temp;
} }
@ -84,11 +110,11 @@ static int is_stack_empty(void)
return (stack == NULL); return (stack == NULL);
} }
static void push(stack_node_t *op) static void push(calc_node_t *op)
{ {
stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t)); stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t));
*z = *op; z->node = *op;
z->next = stack; z->next = stack;
stack = z; stack = z;
} }
@ -330,20 +356,20 @@ void run_operator(calc_node_t *result,
static void evalStack(calc_number_t *number) static void evalStack(calc_number_t *number)
{ {
stack_node_t *op, ip; calc_node_t *op, ip;
unsigned int prec; unsigned int prec;
op = pop(); op = pop();
ip = *op; ip = *op;
prec = operator_list[ip.node.operation].prec; prec = operator_list[ip.operation].prec;
while (!is_stack_empty()) { while (!is_stack_empty()) {
op = pop(); op = pop();
if (prec <= operator_list[op->node.operation].prec) { if (prec <= operator_list[op->operation].prec) {
if (op->node.operation == RPN_OPERATOR_PARENT) continue; if (op->operation == RPN_OPERATOR_PARENT) continue;
calc.prev = ip.node.number; calc.prev = ip.number;
run_operator(&ip.node, &op->node, &ip.node, op->node.operation); run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) { if (calc.is_nan) {
flush_postfix(); flush_postfix();
return; return;
@ -354,17 +380,17 @@ static void evalStack(calc_number_t *number)
} }
} }
if(ip.node.operation != RPN_OPERATOR_EQUAL && ip.node.operation != RPN_OPERATOR_PERCENT) if (ip.operation != RPN_OPERATOR_EQUAL && ip.operation != RPN_OPERATOR_PERCENT)
push(&ip); push(&ip);
calc.prev_operator = op->node.operation; calc.prev_operator = op->operation;
*number = ip.node.number; *number = ip.number;
} }
int exec_infix2postfix(calc_number_t *number, unsigned int func) int exec_infix2postfix(calc_number_t *number, unsigned int func)
{ {
stack_node_t tmp; calc_node_t tmp;
if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) { if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) {
/* if a number has been entered with exponential */ /* if a number has been entered with exponential */
@ -377,10 +403,9 @@ int exec_infix2postfix(calc_number_t *number, unsigned int func)
if (func == RPN_OPERATOR_PERCENT) if (func == RPN_OPERATOR_PERCENT)
percent_mode = TRUE; percent_mode = TRUE;
tmp.node.number = *number; tmp.number = *number;
tmp.node.base = calc.base; tmp.base = calc.base;
tmp.node.operation = func; tmp.operation = func;
tmp.next = NULL;
push(&tmp); push(&tmp);
@ -410,23 +435,23 @@ void exec_change_infix(void)
void exec_closeparent(calc_number_t *number) void exec_closeparent(calc_number_t *number)
{ {
stack_node_t *op, ip; calc_node_t *op, ip;
ip.node.number = *number; ip.number = *number;
ip.node.base = calc.base; ip.base = calc.base;
while (!is_stack_empty()) { while (!is_stack_empty()) {
op = pop(); op = pop();
if (op->node.operation == RPN_OPERATOR_PARENT) if (op->operation == RPN_OPERATOR_PARENT)
break; break;
run_operator(&ip.node, &op->node, &ip.node, op->node.operation); run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) { if (calc.is_nan) {
flush_postfix(); flush_postfix();
return; return;
} }
} }
*number = ip.node.number; *number = ip.number;
} }
int eval_parent_count(void) int eval_parent_count(void)
@ -442,7 +467,7 @@ int eval_parent_count(void)
return n; return n;
} }
void flush_postfix() void flush_postfix(void)
{ {
while (!is_stack_empty()) while (!is_stack_empty())
pop(); pop();
@ -459,4 +484,3 @@ void start_rpn_engine(void)
void stop_rpn_engine(void) void stop_rpn_engine(void)
{ {
} }

View file

@ -1,3 +1,23 @@
/*
* ReactOS Calc (RPN encoder/decoder for GMP/MPFR engine)
*
* Copyright 2007-2017, Carlo Bramini
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "calc.h" #include "calc.h"
typedef struct { typedef struct {
@ -15,7 +35,7 @@ typedef struct {
} calc_operator_t; } calc_operator_t;
static stack_node_t *stack; static stack_node_t *stack;
static stack_node_t temp; static calc_node_t temp;
static BOOL percent_mode; static BOOL percent_mode;
static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b); static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
@ -61,25 +81,27 @@ static const calc_operator_t operator_list[] = {
{ 7, rpn_sqr_f, NULL, NULL, }, // RPN_OPERATOR_SQR { 7, rpn_sqr_f, NULL, NULL, }, // RPN_OPERATOR_SQR
}; };
static void node_copy(stack_node_t *dst, stack_node_t *src) static void node_copy(calc_node_t *dst, calc_node_t *src)
{ {
mpfr_set(dst->node.number.mf,src->node.number.mf,MPFR_DEFAULT_RND); mpfr_set(dst->number.mf, src->number.mf, MPFR_DEFAULT_RND);
dst->node.operation = src->node.operation; dst->operation = src->operation;
dst->next = src->next;
} }
static stack_node_t *pop() static calc_node_t *pop(void)
{ {
void *next;
if (stack == NULL) if (stack == NULL)
return NULL; return NULL;
/* copy the node */ /* copy the node */
node_copy(&temp, stack); node_copy(&temp, &stack->node);
next = stack->next;
/* free the node */ /* free the node */
mpfr_clear(stack->node.number.mf); mpfr_clear(stack->node.number.mf);
free(stack); free(stack);
stack = temp.next; stack = next;
return &temp; return &temp;
} }
@ -89,12 +111,12 @@ static int is_stack_empty(void)
return (stack == NULL); return (stack == NULL);
} }
static void push(stack_node_t *op) static void push(calc_node_t *op)
{ {
stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t)); stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t));
mpfr_init_set(z->node.number.mf,op->node.number.mf,MPFR_DEFAULT_RND); mpfr_init_set(z->node.number.mf, op->number.mf, MPFR_DEFAULT_RND);
z->node.operation = op->node.operation; z->node.operation = op->operation;
z->next = stack; z->next = stack;
stack = z; stack = z;
} }
@ -109,8 +131,7 @@ static unsigned int get_prec(unsigned int opc)
} }
*/ */
typedef typedef void (*exec_call_t)
__GMP_DECLSPEC void (*exec_call_t)
__GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr));
static void rpn_exec_int(calc_number_t *r, calc_number_t *a, calc_number_t *b, exec_call_t cb) static void rpn_exec_int(calc_number_t *r, calc_number_t *a, calc_number_t *b, exec_call_t cb)
@ -286,7 +307,6 @@ static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
} }
} }
void run_operator(calc_node_t *result, void run_operator(calc_node_t *result,
calc_node_t *a, calc_node_t *a,
calc_node_t *b, calc_node_t *b,
@ -307,24 +327,24 @@ void run_operator(calc_node_t *result,
static void evalStack(calc_number_t *number) static void evalStack(calc_number_t *number)
{ {
stack_node_t *op, ip; calc_node_t *op, ip;
unsigned int prec; unsigned int prec;
mpfr_init(ip.node.number.mf); mpfr_init(ip.number.mf);
op = pop(); op = pop();
node_copy(&ip, op); node_copy(&ip, op);
prec = operator_list[ip.node.operation].prec; prec = operator_list[ip.operation].prec;
while (!is_stack_empty()) { while (!is_stack_empty()) {
op = pop(); op = pop();
if (prec <= operator_list[op->node.operation].prec) { if (prec <= operator_list[op->operation].prec) {
if (op->node.operation == RPN_OPERATOR_PARENT) continue; if (op->operation == RPN_OPERATOR_PARENT) continue;
rpn_copy(&calc.prev, &ip.node.number); rpn_copy(&calc.prev, &ip.number);
run_operator(&ip.node, &op->node, &ip.node, op->node.operation); run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) { if (calc.is_nan) {
flush_postfix(); flush_postfix();
mpfr_clear(ip.node.number.mf); mpfr_clear(ip.number.mf);
return; return;
} }
} else { } else {
@ -333,18 +353,18 @@ static void evalStack(calc_number_t *number)
} }
} }
if(ip.node.operation != RPN_OPERATOR_EQUAL && ip.node.operation != RPN_OPERATOR_PERCENT) if (ip.operation != RPN_OPERATOR_EQUAL && ip.operation != RPN_OPERATOR_PERCENT)
push(&ip); push(&ip);
calc.prev_operator = op->node.operation; calc.prev_operator = op->operation;
rpn_copy(number, &ip.node.number); rpn_copy(number, &ip.number);
mpfr_clear(ip.node.number.mf); mpfr_clear(ip.number.mf);
} }
int exec_infix2postfix(calc_number_t *number, unsigned int func) int exec_infix2postfix(calc_number_t *number, unsigned int func)
{ {
stack_node_t tmp; calc_node_t tmp;
if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) { if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) {
/* if a number has been entered with exponential */ /* if a number has been entered with exponential */
@ -357,12 +377,12 @@ int exec_infix2postfix(calc_number_t *number, unsigned int func)
if (func == RPN_OPERATOR_PERCENT) if (func == RPN_OPERATOR_PERCENT)
percent_mode = TRUE; percent_mode = TRUE;
mpfr_init(tmp.node.number.mf); mpfr_init(tmp.number.mf);
rpn_copy(&tmp.node.number, number); rpn_copy(&tmp.number, number);
tmp.node.operation = func; tmp.operation = func;
push(&tmp); push(&tmp);
mpfr_clear(tmp.node.number.mf); mpfr_clear(tmp.number.mf);
if (func == RPN_OPERATOR_NONE) if (func == RPN_OPERATOR_NONE)
return 0; return 0;
@ -390,24 +410,24 @@ void exec_change_infix(void)
void exec_closeparent(calc_number_t *number) void exec_closeparent(calc_number_t *number)
{ {
stack_node_t *op, ip; calc_node_t *op, ip;
rpn_alloc(&ip.node.number); rpn_alloc(&ip.number);
rpn_copy(&ip.node.number, number); rpn_copy(&ip.number, number);
while (!is_stack_empty()) { while (!is_stack_empty()) {
op = pop(); op = pop();
if (op->node.operation == RPN_OPERATOR_PARENT) if (op->operation == RPN_OPERATOR_PARENT)
break; break;
run_operator(&ip.node, &op->node, &ip.node, op->node.operation); run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) { if (calc.is_nan) {
flush_postfix(); flush_postfix();
return; return;
} }
} }
rpn_copy(number, &ip.node.number); rpn_copy(number, &ip.number);
rpn_free(&ip.node.number); rpn_free(&ip.number);
} }
int eval_parent_count(void) int eval_parent_count(void)
@ -423,7 +443,7 @@ int eval_parent_count(void)
return n; return n;
} }
void flush_postfix() void flush_postfix(void)
{ {
while (!is_stack_empty()) while (!is_stack_empty())
pop(); pop();
@ -440,7 +460,7 @@ void start_rpn_engine(void)
mpfr_init(calc.code.mf); mpfr_init(calc.code.mf);
mpfr_init(calc.prev.mf); mpfr_init(calc.prev.mf);
mpfr_init(calc.memory.number.mf); mpfr_init(calc.memory.number.mf);
mpfr_init(temp.node.number.mf); mpfr_init(temp.number.mf);
rpn_zero(&calc.memory.number); rpn_zero(&calc.memory.number);
} }
@ -449,5 +469,5 @@ void stop_rpn_engine(void)
mpfr_clear(calc.code.mf); mpfr_clear(calc.code.mf);
mpfr_clear(calc.prev.mf); mpfr_clear(calc.prev.mf);
mpfr_clear(calc.memory.number.mf); mpfr_clear(calc.memory.number.mf);
mpfr_clear(temp.node.number.mf); mpfr_clear(temp.number.mf);
} }

View file

@ -1,3 +1,23 @@
/*
* ReactOS Calc (Utility functions for IEEE-754 engine)
*
* Copyright 2007-2017, Carlo Bramini
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "calc.h" #include "calc.h"
void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base) void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
@ -7,7 +27,7 @@ void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
switch (base) { switch (base) {
case IDC_RADIO_HEX: case IDC_RADIO_HEX:
_stprintf(buffer, TEXT("%I64X"), rpn->i); _stprintf(buffer, _T("%I64X"), rpn->i);
break; break;
case IDC_RADIO_DEC: case IDC_RADIO_DEC:
/* /*
@ -19,44 +39,44 @@ void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
#define MAX_LD_WIDTH 16 #define MAX_LD_WIDTH 16
/* calculate the width of integer number */ /* calculate the width of integer number */
width = (rpn->f==0) ? 1 : (int)log10(fabs(rpn->f))+1; width = (rpn->f==0) ? 1 : (int)log10(fabs(rpn->f))+1;
if ((calc.sci_out != FALSE) || (width > MAX_LD_WIDTH) || (width < -MAX_LD_WIDTH)) if (calc.sci_out == TRUE || width > MAX_LD_WIDTH || width < -MAX_LD_WIDTH)
_stprintf(buffer, TEXT("%#e"), rpn->f); _stprintf(buffer, _T("%#.*e"), MAX_LD_WIDTH-1, rpn->f);
else { else {
TCHAR *ptr, *dst; TCHAR *ptr, *dst;
ptr = buffer + _stprintf(buffer, TEXT("%#*.*f"), width, ((MAX_LD_WIDTH-width-1)>=0) ? MAX_LD_WIDTH-width-1 : 0, rpn->f); ptr = buffer + _stprintf(buffer, _T("%#*.*f"), width, ((MAX_LD_WIDTH-width-1)>=0) ? MAX_LD_WIDTH-width-1 : 0, rpn->f);
/* format string ensures there is a '.': */ /* format string ensures there is a '.': */
dst = _tcschr(buffer, TEXT('.')); dst = _tcschr(buffer, _T('.'));
while (--ptr > dst) while (--ptr > dst)
if (*ptr != TEXT('0')) if (*ptr != _T('0'))
break; break;
/* put the string terminator for removing the final '0' (if any) */ /* put the string terminator for removing the final '0' (if any) */
ptr[1] = TEXT('\0'); ptr[1] = _T('\0');
/* check if the number finishes with '.' */ /* check if the number finishes with '.' */
if (ptr == dst) if (ptr == dst)
/* remove the dot (it will be re-added later) */ /* remove the dot (it will be re-added later) */
ptr[0] = TEXT('\0'); ptr[0] = _T('\0');
} }
#undef MAX_LD_WIDTH #undef MAX_LD_WIDTH
break; break;
case IDC_RADIO_OCT: case IDC_RADIO_OCT:
_stprintf(buffer, TEXT("%I64o"), rpn->i); _stprintf(buffer, _T("%I64o"), rpn->i);
break; break;
case IDC_RADIO_BIN: case IDC_RADIO_BIN:
if (rpn->i == 0) { if (rpn->i == 0) {
buffer[0] = TEXT('0'); buffer[0] = _T('0');
buffer[1] = TEXT('\0'); buffer[1] = _T('\0');
break; break;
} }
tmp = *rpn; tmp = *rpn;
buffer[0] = TEXT('\0'); buffer[0] = _T('\0');
while (tmp.u) { while (tmp.u) {
memmove(buffer+1, buffer, (size-1)*sizeof(TCHAR)); memmove(buffer+1, buffer, (size-1)*sizeof(TCHAR));
if (tmp.u & 1) if (tmp.u & 1)
calc.buffer[0] = TEXT('1'); buffer[0] = _T('1');
else else
calc.buffer[0] = TEXT('0'); buffer[0] = _T('0');
tmp.u >>= 1; tmp.u >>= 1;
} }
break; break;
@ -69,20 +89,20 @@ void convert_text2number_2(calc_number_t *a)
switch (calc.base) { switch (calc.base) {
case IDC_RADIO_HEX: case IDC_RADIO_HEX:
_stscanf(calc.buffer, TEXT("%I64X"), &(a->i)); _stscanf(calc.buffer, _T("%I64X"), &(a->i));
break; break;
case IDC_RADIO_DEC: case IDC_RADIO_DEC:
_stscanf(calc.buffer, TEXT("%lf"), &(a->f)); _stscanf(calc.buffer, _T("%lf"), &(a->f));
break; break;
case IDC_RADIO_OCT: case IDC_RADIO_OCT:
_stscanf(calc.buffer, TEXT("%I64o"), &(a->i)); _stscanf(calc.buffer, _T("%I64o"), &(a->i));
break; break;
case IDC_RADIO_BIN: case IDC_RADIO_BIN:
ptr = calc.buffer; ptr = calc.buffer;
a->i = 0; a->i = 0;
while (*ptr != TEXT('\0')) { while (*ptr != _T('\0')) {
a->i <<= 1; a->i <<= 1;
if (*ptr++ == TEXT('1')) if (*ptr++ == _T('1'))
a->i |= 1; a->i |= 1;
} }
break; break;

View file

@ -1,3 +1,23 @@
/*
* ReactOS Calc (Utility functions for GMP/MPFR engine)
*
* Copyright 2007-2017, Carlo Bramini
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "calc.h" #include "calc.h"
void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base) void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
@ -39,7 +59,7 @@ void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
width = 1 + mpfr_get_si(t, MPFR_DEFAULT_RND); width = 1 + mpfr_get_si(t, MPFR_DEFAULT_RND);
mpfr_clear(t); mpfr_clear(t);
} }
if ((calc.sci_out != FALSE) || (width > max_ld_width) || (width < -max_ld_width)) if (calc.sci_out == TRUE || width > max_ld_width || width < -max_ld_width)
ptr = temp + gmp_sprintf(temp, "%*.*#Fe", 1, max_ld_width, ff); ptr = temp + gmp_sprintf(temp, "%*.*#Fe", 1, max_ld_width, ff);
else { else {
ptr = temp + gmp_sprintf(temp, "%#*.*Ff", width, ((max_ld_width-width-1)>=0) ? max_ld_width-width-1 : 0, ff); ptr = temp + gmp_sprintf(temp, "%#*.*Ff", width, ((max_ld_width-width-1)>=0) ? max_ld_width-width-1 : 0, ff);
@ -62,8 +82,8 @@ void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
case IDC_RADIO_BIN: case IDC_RADIO_BIN:
/* if the number is zero, just write 0 ;) */ /* if the number is zero, just write 0 ;) */
if (rpn_is_zero(rpn)) { if (rpn_is_zero(rpn)) {
temp[0] = TEXT('0'); temp[0] = _T('0');
temp[1] = TEXT('\0'); temp[1] = _T('\0');
break; break;
} }
/* repeat until a bit set to '1' is found */ /* repeat until a bit set to '1' is found */
@ -78,8 +98,8 @@ void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
} while (1); } while (1);
/* now revert the string into TCHAR buffer */ /* now revert the string into TCHAR buffer */
for (q=0; q<n; q++) for (q=0; q<n; q++)
buffer[n-q-1] = (temp[q] == '1') ? TEXT('1') : TEXT('0'); buffer[n-q-1] = (temp[q] == '1') ? _T('1') : _T('0');
buffer[n] = TEXT('\0'); buffer[n] = _T('\0');
mpz_clear(zz); mpz_clear(zz);
mpf_clear(ff); mpf_clear(ff);
@ -87,7 +107,7 @@ void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
} }
mpz_clear(zz); mpz_clear(zz);
mpf_clear(ff); mpf_clear(ff);
_sntprintf(buffer, SIZEOF(calc.buffer), TEXT("%s"), temp); _sntprintf(buffer, SIZEOF(calc.buffer), _T("%hs"), temp);
} }
void convert_text2number_2(calc_number_t *a) void convert_text2number_2(calc_number_t *a)
@ -135,4 +155,3 @@ void convert_real_integer(unsigned int base)
break; break;
} }
} }

View file

@ -166,6 +166,8 @@ static const WORD operator_codes[] = {
IDC_BUTTON_MULT, // RPN_OPERATOR_MULT IDC_BUTTON_MULT, // RPN_OPERATOR_MULT
IDC_BUTTON_DIV, // RPN_OPERATOR_DIV IDC_BUTTON_DIV, // RPN_OPERATOR_DIV
IDC_BUTTON_MOD, // RPN_OPERATOR_MOD IDC_BUTTON_MOD, // RPN_OPERATOR_MOD
IDC_BUTTON_XeY, // RPN_OPERATOR_POW
IDC_BUTTON_XrY, // RPN_OPERATOR_SQR
}; };
typedef void (*rpn_callback1)(calc_number_t *); typedef void (*rpn_callback1)(calc_number_t *);
@ -180,8 +182,6 @@ typedef struct {
rpn_callback1 inv_hyp; rpn_callback1 inv_hyp;
} function_table_t; } function_table_t;
static void run_pow(calc_number_t *number);
static void run_sqr(calc_number_t *number);
static void run_fe(calc_number_t *number); static void run_fe(calc_number_t *number);
static void run_dat_sta(calc_number_t *number); static void run_dat_sta(calc_number_t *number);
static void run_mp(calc_number_t *c); static void run_mp(calc_number_t *c);
@ -205,10 +205,9 @@ static const function_table_t function_table[] = {
{ IDC_BUTTON_LN, MODIFIER_INV, 1, rpn_ln, rpn_exp, NULL, NULL }, { IDC_BUTTON_LN, MODIFIER_INV, 1, rpn_ln, rpn_exp, NULL, NULL },
{ IDC_BUTTON_LOG, MODIFIER_INV, 1, rpn_log, rpn_exp10, NULL, NULL }, { IDC_BUTTON_LOG, MODIFIER_INV, 1, rpn_log, rpn_exp10, NULL, NULL },
{ IDC_BUTTON_NF, 0, 1, rpn_fact, NULL, NULL, NULL }, { IDC_BUTTON_NF, 0, 1, rpn_fact, NULL, NULL, NULL },
{ IDC_BUTTON_AVE, 0, 0, rpn_ave, NULL, NULL, NULL }, { IDC_BUTTON_AVE, MODIFIER_INV, 0, rpn_ave, rpn_ave2, NULL, NULL },
{ IDC_BUTTON_SUM, 0, 0, rpn_sum, NULL, NULL, NULL }, { IDC_BUTTON_SUM, MODIFIER_INV, 0, rpn_sum, rpn_sum2, NULL, NULL },
{ IDC_BUTTON_S, MODIFIER_INV, 0, rpn_s_m1, rpn_s, NULL, NULL }, { IDC_BUTTON_S, MODIFIER_INV, 0, rpn_s_m1, rpn_s, NULL, NULL },
{ IDC_BUTTON_XeY, MODIFIER_INV, 1, run_pow, run_sqr, NULL, NULL },
{ IDC_BUTTON_SQRT, MODIFIER_INV, 1, rpn_sqrt, NULL, NULL, NULL }, { IDC_BUTTON_SQRT, MODIFIER_INV, 1, rpn_sqrt, NULL, NULL, NULL },
{ IDC_BUTTON_DMS, MODIFIER_INV, 1, rpn_dec2dms, rpn_dms2dec, NULL, NULL }, { IDC_BUTTON_DMS, MODIFIER_INV, 1, rpn_dec2dms, rpn_dms2dec, NULL, NULL },
{ IDC_BUTTON_FE, 0, 1, run_fe, NULL, NULL, NULL }, { IDC_BUTTON_FE, 0, 1, run_fe, NULL, NULL, NULL },
@ -1132,16 +1131,6 @@ static statistic_t *upload_stat_number(int n)
return p; return p;
} }
static void run_pow(calc_number_t *number)
{
exec_infix2postfix(number, RPN_OPERATOR_POW);
}
static void run_sqr(calc_number_t *number)
{
exec_infix2postfix(number, RPN_OPERATOR_SQR);
}
static void run_fe(calc_number_t *number) static void run_fe(calc_number_t *number)
{ {
calc.sci_out = ((calc.sci_out != FALSE) ? FALSE : TRUE); calc.sci_out = ((calc.sci_out != FALSE) ? FALSE : TRUE);
@ -1531,17 +1520,29 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
case IDC_BUTTON_LSH: case IDC_BUTTON_LSH:
case IDC_BUTTON_RSH: case IDC_BUTTON_RSH:
case IDC_BUTTON_EQU: case IDC_BUTTON_EQU:
case IDC_BUTTON_XeY:
case IDC_BUTTON_XrY:
if (calc.is_nan) break; if (calc.is_nan) break;
/* /*
* LSH button holds the RSH function too with INV modifier, * LSH and XeY buttons hold also the RSH and XrY functions with INV modifier,
* but since it's a two operand operator, it must be handled here. * but since they are two operand operators, they must be handled here.
*/ */
if (LOWORD(wp) == IDC_BUTTON_LSH && if ((get_modifiers(hWnd) & MODIFIER_INV))
(get_modifiers(hWnd) & MODIFIER_INV)) { {
PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_BUTTON_RSH, BN_CLICKED), 0); WPARAM IdcSim = IDC_STATIC;
SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
break; switch (LOWORD(wp)) {
case IDC_BUTTON_LSH: IdcSim = MAKEWPARAM(IDC_BUTTON_RSH, BN_CLICKED); break;
case IDC_BUTTON_XeY: IdcSim = MAKEWPARAM(IDC_BUTTON_XrY, BN_CLICKED); break;
}
if (IdcSim != IDC_STATIC)
{
PostMessage(hWnd, WM_COMMAND, IdcSim, 0);
CheckDlgButton(hWnd, IDC_CHECK_INV, BST_UNCHECKED);
}
} }
for (x=0; x<SIZEOF(operator_codes); x++) { for (x=0; x<SIZEOF(operator_codes); x++) {
if (LOWORD(wp) == operator_codes[x]) { if (LOWORD(wp) == operator_codes[x]) {
convert_text2number(&calc.code); convert_text2number(&calc.code);
@ -1668,7 +1669,6 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
case IDC_BUTTON_SIN: case IDC_BUTTON_SIN:
case IDC_BUTTON_COS: case IDC_BUTTON_COS:
case IDC_BUTTON_TAN: case IDC_BUTTON_TAN:
case IDC_BUTTON_XeY:
case IDC_BUTTON_MS: case IDC_BUTTON_MS:
for (x=0; x<SIZEOF(function_table); x++) { for (x=0; x<SIZEOF(function_table); x++) {
if (LOWORD(wp) == function_table[x].idc) { if (LOWORD(wp) == function_table[x].idc) {
@ -1697,8 +1697,8 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
convert_text2number(&calc.code); convert_text2number(&calc.code);
cb(&calc.code); cb(&calc.code);
display_rpn_result(hWnd, &calc.code); display_rpn_result(hWnd, &calc.code);
if (!(function_table[x].range & NO_CHAIN)) // if (!(function_table[x].range & NO_CHAIN))
exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE); // exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
if (function_table[x].range & MODIFIER_INV) if (function_table[x].range & MODIFIER_INV)
SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0); SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
if (function_table[x].range & MODIFIER_HYP) if (function_table[x].range & MODIFIER_HYP)