/* 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. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "number.h" #include #include #include #include // define MPFR_USE_VA_LIST to enable the use of mpfr_inits and mpfr_clears #define MPFR_USE_VA_LIST #include #include "istring.h" #include "definitions.cpp" #include "tools.h" #include "rational.h" #include "array.h" #include "parse_file.h" // init int init_Number(Number* number, int memory){ (*number).scalars=calloc(memory,sizeof(Q)); (*number).base=calloc(memory,sizeof(int)); (*number).memory=memory; (*number).length=0; return(0); } int free_Number(Number number){ free(number.scalars); free(number.base); return(0); } // copy int number_cpy(Number input, Number* output){ init_Number(output,input.length); number_cpy_noinit(input,output); return(0); } int number_cpy_noinit(Number input, Number* output){ int i; if((*output).memory=(*output).memory){ number_resize(output,2*(*output).memory); } (*output).scalars[(*output).length]=scalar; (*output).base[(*output).length]=base; (*output).length++; // not optimal number_sort(*output,0,(*output).length-1); return(0); } // concatenate int number_concat(Number input, Number* output){ int i; int offset=(*output).length; if((*output).length+input.length>(*output).memory){ // make it longer than needed by (*output).length (for speed) number_resize(output,2*(*output).length+input.length); } for(i=0;i=0){ (*inout).scalars[index]=Q_add((*inout).scalars[index], scalar); } else{ number_append(scalar, base, inout); } return(0); } // create a new number int number_add(Number x1, Number x2, Number* out){ number_cpy(x1,out); number_add_chain(x2,out); return(0); } // return the number Number number_add_ret(Number x1, Number x2){ Number out; number_add(x1,x2,&out); return(out); } // multiply int number_prod(Number x1, Number x2, Number* out){ int i,j; int div; Q new_scalar; int new_base; init_Number(out, x1.length); for(i=0;i0){ 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{ // 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); } // not inplace int number_quot(Number x1, Number x2, Number* output){ 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* 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){ Number ret; number_quot(x1, x2, &ret); return(ret); } // remove 0's int number_simplify(Number in, Number* out){ int i; init_Number(out, in.length); for(i=0;i0){ char_array_snprintf(out," + "); } if(simp.length>1 || (simp.length==1 && simp.base[0]!=1)){ char_array_append('(',out); } Q_sprint(simp.scalars[i], out); if(simp.length>1 || (simp.length==1 && simp.base[0]!=1)){ char_array_append(')',out); } if(simp.base[i]!=1){ char_array_snprintf(out,"s{%d}",simp.base[i]); } } free_Number(simp); return(0); } // print to stdout int number_print(Number number){ Char_Array buffer; init_Char_Array(&buffer,5*number.length); number_sprint(number, &buffer); printf("%s",char_array_to_str_noinit(&buffer)); return(0); } #define PP_NULL_MODE 0 #define PP_NUM_MODE 1 #define PP_SQRT_MODE 2 // read from a string int str_to_Number(char* str, Number* number){ char* ptr; int mode; char* buffer=calloc(str_len(str)+1,sizeof(char)); char* buffer_ptr=buffer; Q num; int base; 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 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=aux_str;*ptr!='\0';ptr++){ switch(*ptr){ // read number case '(': if(mode==PP_NULL_MODE){ // init base base=1; mode=PP_NUM_MODE; } else{ fprintf(stderr,"syntax error: misplaced '(' in number '%s'\n",str); exit(-1); } break; case ')': if(mode==PP_NUM_MODE){ str_to_Q(buffer,&num); buffer_ptr=buffer; *buffer_ptr='\0'; mode=PP_NULL_MODE; } else{ fprintf(stderr,"syntax error: mismatched ')' in number '%s'\n",str); exit(-1); } break; // read sqrt case '{': // init num if(num.numerator==0){ num=quot(1,1); } if(mode==PP_NULL_MODE){ mode=PP_SQRT_MODE; } else{ fprintf(stderr,"syntax error: misplaced '{' in number '%s'\n",str); exit(-1); } break; case '}': if(mode==PP_SQRT_MODE){ 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 case '+': if(mode==PP_NULL_MODE){ number_add_elem(num, base, number); // re-init num and base 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; } } if(mode==PP_NULL_MODE){ 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); } // with Char_Array input int char_array_to_Number(Char_Array cstr_num,Number* output){ char* buffer; char_array_to_str(cstr_num,&buffer); str_to_Number(buffer, output); free(buffer); return(0); } // -------------------- Number_Matrix --------------------- // init int init_Number_Matrix(Number_Matrix* matrix, int length){ int i,j; (*matrix).matrix=calloc(length,sizeof(Number*)); (*matrix).indices=calloc(length,sizeof(int)); for(i=0;i