Ian Jauslin
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/number.c')
-rw-r--r--src/number.c223
1 files changed, 175 insertions, 48 deletions
diff --git a/src/number.c b/src/number.c
index e63427f..5bc87de 100644
--- a/src/number.c
+++ b/src/number.c
@@ -1,5 +1,5 @@
/*
-Copyright 2015 Ian Jauslin
+Copyright 2015-2022 Ian Jauslin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ limitations under the License.
#include "tools.h"
#include "rational.h"
#include "array.h"
+#include "parse_file.h"
// init
int init_Number(Number* number, int memory){
@@ -271,50 +272,107 @@ Number number_Qprod_ret(Q q, Number x){
return(ret);
}
-// inverse
-int number_inverse_inplace(Number* inout){
- int i;
- for(i=0;i<(*inout).length;i++){
- if((*inout).base[i]>0){
- (*inout).scalars[i]=Q_inverse((*inout).scalars[i]);
- (*inout).scalars[i].denominator*=(*inout).base[i];
+// quotient of two numbers
+// recursively simplify numerator/denominator until denominator only has one term
+// the output is set to 'numerator'
+// both numerator and denominator may be changed by this function
+// this algorithm is not optimal in cases where denominator has several terms, in particular if their bases are large
+// it is optimal if denominator only has one term
+int number_quot_inplace(Number* numerator, Number* denominator){
+ Number tmp;
+ int i,factor;
+
+ switch((*denominator).length){
+ // error
+ case 0:
+ fprintf(stderr,"error: attempting to invert 0\n");
+ exit(-1);
+ break;
+
+ // trivial case
+ case 1:
+ // trivial base
+ if((*denominator).base[0]==1){
+ number_Qprod_chain(Q_inverse((*denominator).scalars[0]), numerator);
}
- else if((*inout).base[i]<0){
- (*inout).scalars[i]=Q_inverse((*inout).scalars[i]);
- (*inout).scalars[i].denominator*=-(*inout).base[i];
- (*inout).scalars[i].numerator*=-1;
+ // non-trivial base
+ else{
+ // set tmp=1/denominator
+ tmp=number_one();
+ tmp.base[0]=(*denominator).base[0];
+ tmp.scalars[0].denominator=(*denominator).scalars[0].numerator*abs((*denominator).base[0]);
+ if((*denominator).base[0]>0){
+ tmp.scalars[0].numerator=(*denominator).scalars[0].denominator;
+ }
+ else if((*denominator).base[0]<0){
+ tmp.scalars[0].numerator=-(*denominator).scalars[0].denominator;
+ }
+ else{
+ fprintf(stderr,"error: attempting to invert 0\n");
+ exit(-1);
+ }
+ number_prod_chain(tmp, numerator);
+ }
+ break;
+
+ default:
+ // find non-trivial basis
+ for(i=0;(*denominator).base[i]==1;i++){}
+
+ // smallest prime factor of the base
+ if((*denominator).base[i]<0){
+ factor=-1;
+ }
+ else if((*denominator).base[i]==2){
+ factor=2;
}
else{
- fprintf(stderr,"error: attempting to invert 0\n");
- exit(-1);
+ // COMMENT: this is not optimal, but, provided the basis is not too large, this should not be a problem
+ for(factor=3;is_factor(factor, (*denominator).base[i])==0;factor=factor+2){}
+ }
+
+ // tmp is set to ((terms that k does not divide)-(terms that k divides))
+ // tmp will be multiplied to numerator and denominator
+ init_Number(&tmp,(*denominator).length);
+
+ // find all terms whose base is a multiple of k
+ for(i=0;i<(*denominator).length;i++){
+ if(is_factor(factor, (*denominator).base[i])){
+ // add to tmp with a - sign
+ number_add_elem(quot(-(*denominator).scalars[i].numerator,(*denominator).scalars[i].denominator), (*denominator).base[i], &tmp);
+ }
+ else{
+ // add to tmp
+ number_add_elem((*denominator).scalars[i], (*denominator).base[i], &tmp);
+ }
}
+
+ number_prod_chain(tmp, numerator);
+ number_prod_chain(tmp, denominator);
+ free_Number(tmp);
+
+ // recurse
+ number_quot_inplace(numerator, denominator);
}
+
return(0);
}
-// write to output
-int number_inverse(Number input, Number* output){
- number_cpy(input,output);
- number_inverse_inplace(output);
- return(0);
-}
-// return result
-Number number_inverse_ret(Number x){
- Number ret;
- number_inverse(x,&ret);
- return(ret);
-}
-// quotient
+// not inplace
int number_quot(Number x1, Number x2, Number* output){
- Number inv;
- number_inverse(x2, &inv);
- number_prod(x1, inv, output);
- free_Number(inv);
+ Number numerator, denominator;
+ number_cpy(x1, &numerator);
+ number_cpy(x2, &denominator);
+ number_quot_inplace(&numerator, &denominator);
+ *output=numerator;
+ free_Number(denominator);
return(0);
}
-int number_quot_chain(Number x1, Number* inout){
- number_inverse_inplace(inout);
- number_prod_chain(x1, inout);
+int number_quot_chain(Number* inout, Number x2){
+ Number tmp;
+ number_quot(*inout,x2,&tmp);
+ free_Number(*inout);
+ *inout=tmp;
return(0);
}
Number number_quot_ret(Number x1, Number x2){
@@ -419,7 +477,7 @@ int number_print(Number number){
Char_Array buffer;
init_Char_Array(&buffer,5*number.length);
number_sprint(number, &buffer);
- printf("%s",buffer.str);
+ printf("%s",char_array_to_str_noinit(&buffer));
return(0);
}
@@ -434,18 +492,54 @@ int str_to_Number(char* str, Number* number){
char* buffer_ptr=buffer;
Q num;
int base;
- // whether there are parentheses in the string
- int exist_parenthesis=0;
+ int ret;
+ int j;
+ char* aux_str;
+ int aux_free=0;
init_Number(number, NUMBER_SIZE);
+ // check whether the string is blank (return 0 in that case)
+ for(ptr=str;*ptr!='\0';ptr++){
+ if(*ptr!=' ' && *ptr!='\n'){
+ break;
+ }
+ }
+ // blank string
+ if(*ptr=='\0'){
+ number_add_elem(quot(0,1), 1, number);
+ free(buffer);
+ return(0);
+ }
+
// init num and base
- // init to 0 so that if str is empty, then the number is set to 0
- num=quot(0,1);
+ num=quot(1,1);
base=1;
+ // check whether the str only contains a rational number, and add parentheses
+ // keep rtack of the length of str
+ for(j=0,ptr=str;*ptr!='\0';j++,ptr++){
+ if((*ptr<'0' || *ptr>'9') && *ptr!='-' && *ptr!='/'){
+ break;
+ }
+ }
+ // only rational
+ if(*ptr=='\0'){
+ aux_str=calloc(j+3,sizeof(char));
+ aux_str[0]='(';
+ for(j=0,ptr=str;*ptr!='\0';ptr++,j++){
+ aux_str[j+1]=*ptr;
+ }
+ aux_str[j+1]=')';
+ aux_str[j+2]='\0';
+ aux_free=1;
+ }
+ else{
+ aux_str=str;
+ }
+
mode=PP_NULL_MODE;
- for(ptr=str;*ptr!='\0';ptr++){
+ for(ptr=aux_str;*ptr!='\0';ptr++){
switch(*ptr){
// read number
case '(':
@@ -453,7 +547,10 @@ int str_to_Number(char* str, Number* number){
// init base
base=1;
mode=PP_NUM_MODE;
- exist_parenthesis=1;
+ }
+ else{
+ fprintf(stderr,"syntax error: misplaced '(' in number '%s'\n",str);
+ exit(-1);
}
break;
case ')':
@@ -463,6 +560,10 @@ int str_to_Number(char* str, Number* number){
*buffer_ptr='\0';
mode=PP_NULL_MODE;
}
+ else{
+ fprintf(stderr,"syntax error: mismatched ')' in number '%s'\n",str);
+ exit(-1);
+ }
break;
// read sqrt
@@ -474,16 +575,26 @@ int str_to_Number(char* str, Number* number){
if(mode==PP_NULL_MODE){
mode=PP_SQRT_MODE;
}
- // if there is a square root, then do not read a fraction (see end of loop)
- exist_parenthesis=1;
+ else{
+ fprintf(stderr,"syntax error: misplaced '{' in number '%s'\n",str);
+ exit(-1);
+ }
break;
case '}':
if(mode==PP_SQRT_MODE){
- sscanf(buffer,"%d",&base);
+ ret=read_int(buffer,&base);
+ if(ret<0){
+ fprintf(stderr,"syntax error: number base should be an integer, got '%s' in '%s'",buffer,str);
+ exit(-1);
+ }
buffer_ptr=buffer;
*buffer_ptr='\0';
mode=PP_NULL_MODE;
}
+ else{
+ fprintf(stderr,"syntax error: mismatched '}' in number '%s'\n",str);
+ exit(-1);
+ }
break;
// write num
@@ -494,24 +605,40 @@ int str_to_Number(char* str, Number* number){
num=quot(0,1);
base=1;
}
+ else{
+ fprintf(stderr,"syntax error: misplaced '+' in number '%s'\n",str);
+ exit(-1);
+ }
break;
+ // ignore 's', ' ' and '\n'
+ case 's':break;
+ case ' ':break;
+ case '\n':break;
default:
if(mode!=PP_NULL_MODE){
buffer_ptr=str_addchar(buffer_ptr,*ptr);
}
+ else{
+ fprintf(stderr,"syntax error: unrecognized character '%c' in number '%s'\n",*ptr,str);
+ exit(-1);
+ }
break;
}
}
- // last step
if(mode==PP_NULL_MODE){
- if(exist_parenthesis==0){
- str_to_Q(str, &num);
- }
number_add_elem(num, base, number);
}
+ else{
+ fprintf(stderr,"syntax error: mismatched '(' in number '%s'\n",str);
+ exit(-1);
+ }
+
+ if(aux_free==1){
+ free(aux_str);
+ }
free(buffer);
return(0);
}