[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
#include <htmlhelp.h>
#endif
#include <limits.h>
/* Messages reserved for the main dialog */
#define WM_CLOSE_STATS (WM_APP+1)
@ -21,8 +22,9 @@
#define WM_HANDLE_FROM (WM_APP+6)
#define WM_HANDLE_TO (WM_APP+7)
/* GNU MULTI-PRECISION LIBRARY support */
#ifdef ENABLE_MULTI_PRECISION
#include <mpfr.h>
#include "mpfr.h"
#ifndef MPFR_DEFAULT_RND
#define MPFR_DEFAULT_RND mpfr_get_default_rounding_mode ()
@ -155,11 +157,11 @@ typedef struct {
extern calc_t calc;
#define CALC_E 2.7182818284590452354
#define CALC_PI_2 1.57079632679489661923
#define CALC_PI 3.14159265358979323846
#define CALC_3_PI_2 4.71238898038468985769
/* IEEE constants */
#define CALC_E 2.718281828459045235360
#define CALC_PI_2 1.570796326794896619231
#define CALC_PI 3.141592653589793238462
#define CALC_3_PI_2 4.712388980384689857694
#define CALC_2_PI 6.283185307179586476925
#define MODIFIER_INV 0x01
@ -167,14 +169,9 @@ extern calc_t calc;
#define NO_CHAIN 0x04
void apply_int_mask(calc_number_t *a);
#ifdef ENABLE_MULTI_PRECISION
void validate_rad2angle(calc_number_t *c);
void validate_angle2rad(calc_number_t *c);
#else
#ifndef ENABLE_MULTI_PRECISION
__int64 logic_dbl2int(calc_number_t *a);
double logic_int2dbl(calc_number_t *a);
double validate_rad2angle(double a);
double validate_angle2rad(calc_number_t *c);
#endif
void rpn_sin(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_log(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_sum2(calc_number_t *c);
void rpn_s(calc_number_t *c);
void rpn_s_m1(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_free(calc_number_t *c);
//
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_real_integer(unsigned int base);
//
INT_PTR CALLBACK AboutDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
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 <limits.h>
static double validate_rad2angle(double a);
static double validate_angle2rad(calc_number_t *c);
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;
}
double validate_rad2angle(double a)
static double validate_rad2angle(double a)
{
switch (calc.degr) {
case IDC_RADIO_DEG:
@ -62,7 +83,7 @@ double validate_rad2angle(double a)
return a;
}
double validate_angle2rad(calc_number_t *c)
static double validate_angle2rad(calc_number_t *c)
{
switch (calc.degr) {
case IDC_RADIO_DEG:
@ -250,6 +271,7 @@ __int64 logic_dbl2int(calc_number_t *a)
}
return (__int64)int_part;
}
double logic_int2dbl(calc_number_t *a)
{
return (double)a->i;
@ -315,9 +337,9 @@ static unsigned __int64 sqrti(unsigned __int64 number)
unsigned __int64 n, n1;
#ifdef __GNUC__
if (number == 0xffffffffffffffffLL)
if (number == 0xffffffffffffffffULL)
#else
if (number == 0xffffffffffffffff)
if (number == 0xffffffffffffffffUI64)
#endif
return 0xffffffff;
@ -427,6 +449,21 @@ static double stat_sum(void)
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)
{
double ave = 0;
@ -443,6 +480,22 @@ void rpn_ave(calc_number_t *c)
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)
{
double sum = stat_sum();
@ -453,6 +506,16 @@ void rpn_sum(calc_number_t *c)
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)
{
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"
static void validate_rad2angle(calc_number_t *c);
static void validate_angle2rad(calc_number_t *c);
void apply_int_mask(calc_number_t *r)
{
mpz_t a, mask;
@ -28,7 +51,7 @@ void apply_int_mask(calc_number_t *r)
mpz_clear(mask);
}
void validate_rad2angle(calc_number_t *r)
static void validate_rad2angle(calc_number_t *r)
{
mpfr_t mult, divs;
@ -55,7 +78,7 @@ void validate_rad2angle(calc_number_t *r)
mpfr_clear(divs);
}
void validate_angle2rad(calc_number_t *r)
static void validate_angle2rad(calc_number_t *r)
{
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)
{
int n;
@ -355,6 +393,20 @@ void rpn_ave(calc_number_t *c)
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)
{
stat_sum(c->mf);
@ -363,6 +415,14 @@ void rpn_sum(calc_number_t *c)
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)
{
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:
[Ave]
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]
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]
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]
It inserts the number shown into the output display into the list.
@ -483,10 +489,12 @@ Shortcut from keyboard: CTRL-S
Ave
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
Sum
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
s

View file

@ -101,6 +101,7 @@
#define IDC_COMBO_FROM 1091
#define IDC_COMBO_TO 1092
#define IDC_BUTTON_RSH 1093
#define IDC_BUTTON_XrY 1094
/* TYPES OF CONVERSIONS */
#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"
typedef struct {
@ -15,7 +35,7 @@ typedef struct {
} calc_operator_t;
static stack_node_t *stack;
static stack_node_t temp;
static calc_node_t temp;
static BOOL percent_mode;
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
};
static stack_node_t *pop(void)
static calc_node_t *pop(void)
{
void *next;
if (stack == NULL)
return NULL;
temp = *stack;
/* copy the node */
temp = stack->node;
next = stack->next;
/* free the node */
free(stack);
stack = temp.next;
stack = next;
return &temp;
}
@ -84,11 +110,11 @@ static int is_stack_empty(void)
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));
*z = *op;
z->node = *op;
z->next = stack;
stack = z;
}
@ -330,20 +356,20 @@ void run_operator(calc_node_t *result,
static void evalStack(calc_number_t *number)
{
stack_node_t *op, ip;
calc_node_t *op, ip;
unsigned int prec;
op = pop();
ip = *op;
prec = operator_list[ip.node.operation].prec;
prec = operator_list[ip.operation].prec;
while (!is_stack_empty()) {
op = pop();
if (prec <= operator_list[op->node.operation].prec) {
if (op->node.operation == RPN_OPERATOR_PARENT) continue;
if (prec <= operator_list[op->operation].prec) {
if (op->operation == RPN_OPERATOR_PARENT) continue;
calc.prev = ip.node.number;
run_operator(&ip.node, &op->node, &ip.node, op->node.operation);
calc.prev = ip.number;
run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) {
flush_postfix();
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);
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)
{
stack_node_t tmp;
calc_node_t tmp;
if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) {
/* 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)
percent_mode = TRUE;
tmp.node.number = *number;
tmp.node.base = calc.base;
tmp.node.operation = func;
tmp.next = NULL;
tmp.number = *number;
tmp.base = calc.base;
tmp.operation = func;
push(&tmp);
@ -410,23 +435,23 @@ void exec_change_infix(void)
void exec_closeparent(calc_number_t *number)
{
stack_node_t *op, ip;
calc_node_t *op, ip;
ip.node.number = *number;
ip.node.base = calc.base;
ip.number = *number;
ip.base = calc.base;
while (!is_stack_empty()) {
op = pop();
if (op->node.operation == RPN_OPERATOR_PARENT)
if (op->operation == RPN_OPERATOR_PARENT)
break;
run_operator(&ip.node, &op->node, &ip.node, op->node.operation);
run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) {
flush_postfix();
return;
}
}
*number = ip.node.number;
*number = ip.number;
}
int eval_parent_count(void)
@ -442,7 +467,7 @@ int eval_parent_count(void)
return n;
}
void flush_postfix()
void flush_postfix(void)
{
while (!is_stack_empty())
pop();
@ -459,4 +484,3 @@ void start_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"
typedef struct {
@ -15,7 +35,7 @@ typedef struct {
} calc_operator_t;
static stack_node_t *stack;
static stack_node_t temp;
static calc_node_t temp;
static BOOL percent_mode;
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
};
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);
dst->node.operation = src->node.operation;
dst->next = src->next;
mpfr_set(dst->number.mf, src->number.mf, MPFR_DEFAULT_RND);
dst->operation = src->operation;
}
static stack_node_t *pop()
static calc_node_t *pop(void)
{
void *next;
if (stack == NULL)
return NULL;
/* copy the node */
node_copy(&temp, stack);
node_copy(&temp, &stack->node);
next = stack->next;
/* free the node */
mpfr_clear(stack->node.number.mf);
free(stack);
stack = temp.next;
stack = next;
return &temp;
}
@ -89,12 +111,12 @@ static int is_stack_empty(void)
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));
mpfr_init_set(z->node.number.mf,op->node.number.mf,MPFR_DEFAULT_RND);
z->node.operation = op->node.operation;
mpfr_init_set(z->node.number.mf, op->number.mf, MPFR_DEFAULT_RND);
z->node.operation = op->operation;
z->next = stack;
stack = z;
}
@ -109,8 +131,7 @@ static unsigned int get_prec(unsigned int opc)
}
*/
typedef
__GMP_DECLSPEC void (*exec_call_t)
typedef void (*exec_call_t)
__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)
@ -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,
calc_node_t *a,
calc_node_t *b,
@ -307,44 +327,44 @@ void run_operator(calc_node_t *result,
static void evalStack(calc_number_t *number)
{
stack_node_t *op, ip;
calc_node_t *op, ip;
unsigned int prec;
mpfr_init(ip.node.number.mf);
mpfr_init(ip.number.mf);
op = pop();
node_copy(&ip, op);
prec = operator_list[ip.node.operation].prec;
prec = operator_list[ip.operation].prec;
while (!is_stack_empty()) {
op = pop();
if (prec <= operator_list[op->node.operation].prec) {
if (op->node.operation == RPN_OPERATOR_PARENT) continue;
if (prec <= operator_list[op->operation].prec) {
if (op->operation == RPN_OPERATOR_PARENT) continue;
rpn_copy(&calc.prev, &ip.node.number);
run_operator(&ip.node, &op->node, &ip.node, op->node.operation);
rpn_copy(&calc.prev, &ip.number);
run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) {
flush_postfix();
mpfr_clear(ip.node.number.mf);
mpfr_clear(ip.number.mf);
return;
}
} else {
push(op);
break;
}
}
}
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);
calc.prev_operator = op->node.operation;
calc.prev_operator = op->operation;
rpn_copy(number, &ip.node.number);
mpfr_clear(ip.node.number.mf);
rpn_copy(number, &ip.number);
mpfr_clear(ip.number.mf);
}
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 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)
percent_mode = TRUE;
mpfr_init(tmp.node.number.mf);
rpn_copy(&tmp.node.number, number);
tmp.node.operation = func;
mpfr_init(tmp.number.mf);
rpn_copy(&tmp.number, number);
tmp.operation = func;
push(&tmp);
mpfr_clear(tmp.node.number.mf);
mpfr_clear(tmp.number.mf);
if (func == RPN_OPERATOR_NONE)
return 0;
@ -390,24 +410,24 @@ void exec_change_infix(void)
void exec_closeparent(calc_number_t *number)
{
stack_node_t *op, ip;
calc_node_t *op, ip;
rpn_alloc(&ip.node.number);
rpn_copy(&ip.node.number, number);
rpn_alloc(&ip.number);
rpn_copy(&ip.number, number);
while (!is_stack_empty()) {
op = pop();
if (op->node.operation == RPN_OPERATOR_PARENT)
if (op->operation == RPN_OPERATOR_PARENT)
break;
run_operator(&ip.node, &op->node, &ip.node, op->node.operation);
run_operator(&ip, op, &ip, op->operation);
if (calc.is_nan) {
flush_postfix();
return;
}
}
rpn_copy(number, &ip.node.number);
rpn_free(&ip.node.number);
rpn_copy(number, &ip.number);
rpn_free(&ip.number);
}
int eval_parent_count(void)
@ -423,12 +443,12 @@ int eval_parent_count(void)
return n;
}
void flush_postfix()
void flush_postfix(void)
{
while (!is_stack_empty())
pop();
/* clear prev and last typed operators */
calc.prev_operator =
calc.prev_operator =
calc.last_operator = 0;
}
@ -440,7 +460,7 @@ void start_rpn_engine(void)
mpfr_init(calc.code.mf);
mpfr_init(calc.prev.mf);
mpfr_init(calc.memory.number.mf);
mpfr_init(temp.node.number.mf);
mpfr_init(temp.number.mf);
rpn_zero(&calc.memory.number);
}
@ -449,5 +469,5 @@ void stop_rpn_engine(void)
mpfr_clear(calc.code.mf);
mpfr_clear(calc.prev.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"
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) {
case IDC_RADIO_HEX:
_stprintf(buffer, TEXT("%I64X"), rpn->i);
_stprintf(buffer, _T("%I64X"), rpn->i);
break;
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
/* calculate the width of integer number */
width = (rpn->f==0) ? 1 : (int)log10(fabs(rpn->f))+1;
if ((calc.sci_out != FALSE) || (width > MAX_LD_WIDTH) || (width < -MAX_LD_WIDTH))
_stprintf(buffer, TEXT("%#e"), rpn->f);
if (calc.sci_out == TRUE || width > MAX_LD_WIDTH || width < -MAX_LD_WIDTH)
_stprintf(buffer, _T("%#.*e"), MAX_LD_WIDTH-1, rpn->f);
else {
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 '.': */
dst = _tcschr(buffer, TEXT('.'));
dst = _tcschr(buffer, _T('.'));
while (--ptr > dst)
if (*ptr != TEXT('0'))
if (*ptr != _T('0'))
break;
/* 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 '.' */
if (ptr == dst)
/* remove the dot (it will be re-added later) */
ptr[0] = TEXT('\0');
ptr[0] = _T('\0');
}
#undef MAX_LD_WIDTH
break;
case IDC_RADIO_OCT:
_stprintf(buffer, TEXT("%I64o"), rpn->i);
_stprintf(buffer, _T("%I64o"), rpn->i);
break;
case IDC_RADIO_BIN:
if (rpn->i == 0) {
buffer[0] = TEXT('0');
buffer[1] = TEXT('\0');
buffer[0] = _T('0');
buffer[1] = _T('\0');
break;
}
tmp = *rpn;
buffer[0] = TEXT('\0');
buffer[0] = _T('\0');
while (tmp.u) {
memmove(buffer+1, buffer, (size-1)*sizeof(TCHAR));
if (tmp.u & 1)
calc.buffer[0] = TEXT('1');
buffer[0] = _T('1');
else
calc.buffer[0] = TEXT('0');
buffer[0] = _T('0');
tmp.u >>= 1;
}
break;
@ -69,20 +89,20 @@ void convert_text2number_2(calc_number_t *a)
switch (calc.base) {
case IDC_RADIO_HEX:
_stscanf(calc.buffer, TEXT("%I64X"), &(a->i));
_stscanf(calc.buffer, _T("%I64X"), &(a->i));
break;
case IDC_RADIO_DEC:
_stscanf(calc.buffer, TEXT("%lf"), &(a->f));
_stscanf(calc.buffer, _T("%lf"), &(a->f));
break;
case IDC_RADIO_OCT:
_stscanf(calc.buffer, TEXT("%I64o"), &(a->i));
_stscanf(calc.buffer, _T("%I64o"), &(a->i));
break;
case IDC_RADIO_BIN:
ptr = calc.buffer;
a->i = 0;
while (*ptr != TEXT('\0')) {
while (*ptr != _T('\0')) {
a->i <<= 1;
if (*ptr++ == TEXT('1'))
if (*ptr++ == _T('1'))
a->i |= 1;
}
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"
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);
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);
else {
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:
/* if the number is zero, just write 0 ;) */
if (rpn_is_zero(rpn)) {
temp[0] = TEXT('0');
temp[1] = TEXT('\0');
temp[0] = _T('0');
temp[1] = _T('\0');
break;
}
/* 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);
/* now revert the string into TCHAR buffer */
for (q=0; q<n; q++)
buffer[n-q-1] = (temp[q] == '1') ? TEXT('1') : TEXT('0');
buffer[n] = TEXT('\0');
buffer[n-q-1] = (temp[q] == '1') ? _T('1') : _T('0');
buffer[n] = _T('\0');
mpz_clear(zz);
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);
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)
@ -135,4 +155,3 @@ void convert_real_integer(unsigned int base)
break;
}
}

View file

@ -166,6 +166,8 @@ static const WORD operator_codes[] = {
IDC_BUTTON_MULT, // RPN_OPERATOR_MULT
IDC_BUTTON_DIV, // RPN_OPERATOR_DIV
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 *);
@ -180,8 +182,6 @@ typedef struct {
rpn_callback1 inv_hyp;
} 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_dat_sta(calc_number_t *number);
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_LOG, MODIFIER_INV, 1, rpn_log, rpn_exp10, NULL, NULL },
{ IDC_BUTTON_NF, 0, 1, rpn_fact, NULL, NULL, NULL },
{ IDC_BUTTON_AVE, 0, 0, rpn_ave, NULL, NULL, NULL },
{ IDC_BUTTON_SUM, 0, 0, rpn_sum, NULL, NULL, NULL },
{ IDC_BUTTON_AVE, MODIFIER_INV, 0, rpn_ave, rpn_ave2, 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_XeY, MODIFIER_INV, 1, run_pow, run_sqr, 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_FE, 0, 1, run_fe, NULL, NULL, NULL },
@ -1132,16 +1131,6 @@ static statistic_t *upload_stat_number(int n)
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)
{
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_RSH:
case IDC_BUTTON_EQU:
case IDC_BUTTON_XeY:
case IDC_BUTTON_XrY:
if (calc.is_nan) break;
/*
* LSH button holds the RSH function too with INV modifier,
* but since it's a two operand operator, it must be handled here.
* LSH and XeY buttons hold also the RSH and XrY functions with INV modifier,
* but since they are two operand operators, they must be handled here.
*/
if (LOWORD(wp) == IDC_BUTTON_LSH &&
(get_modifiers(hWnd) & MODIFIER_INV)) {
PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_BUTTON_RSH, BN_CLICKED), 0);
SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
break;
if ((get_modifiers(hWnd) & MODIFIER_INV))
{
WPARAM IdcSim = IDC_STATIC;
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++) {
if (LOWORD(wp) == operator_codes[x]) {
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_COS:
case IDC_BUTTON_TAN:
case IDC_BUTTON_XeY:
case IDC_BUTTON_MS:
for (x=0; x<SIZEOF(function_table); x++) {
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);
cb(&calc.code);
display_rpn_result(hWnd, &calc.code);
if (!(function_table[x].range & NO_CHAIN))
exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
// if (!(function_table[x].range & NO_CHAIN))
// exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
if (function_table[x].range & MODIFIER_INV)
SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
if (function_table[x].range & MODIFIER_HYP)