dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/RS/dyadic.h

431 lines
15 KiB
C
Raw Normal View History

// Copyright (c) 2006-2013 INRIA Nancy-Grand Est (France). All rights reserved.
//
2020-10-13 12:44:25 +00:00
// This file is part of CGAL (www.cgal.org)
//
2020-10-13 12:44:25 +00:00
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Algebraic_kernel_d/include/CGAL/RS/dyadic.h $
// $Id: dyadic.h 52164b1 2019-10-19T15:34:59+02:00 Sébastien Loriot
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author: Luis Peñaranda <luis.penaranda@gmx.com>
#ifndef CGAL_RS_DYADIC_H
#define CGAL_RS_DYADIC_H
#include <stdio.h>
#include <math.h>
#include <gmp.h>
#include <mpfr.h>
#include <CGAL/assertions.h>
// for c++, compile with -lgmpxx
#ifdef __cplusplus
#include <iostream>
#endif
#define CGALRS_dyadic_struct __mpfr_struct
#define CGALRS_dyadic_t mpfr_t
#define CGALRS_dyadic_ptr mpfr_ptr
#define CGALRS_dyadic_srcptr mpfr_srcptr
// some auxiliary defines
#define CGALRS_dyadic_set_prec(D,P) \
( mpfr_set_prec( (D), (P)>MPFR_PREC_MIN?(P):MPFR_PREC_MIN) )
#define CGALRS_dyadic_prec_round(D,P) \
( mpfr_prec_round( (D), (P)>MPFR_PREC_MIN?(P):MPFR_PREC_MIN, GMP_RNDN) )
#define CGALRS_dyadic_set_exp(D,E) \
( CGAL_assertion( (E) <= mpfr_get_emax() && \
(E) >= mpfr_get_emin() ) ,\
mpfr_set_exp(D,E) )
// init functions
#define CGALRS_dyadic_init(D) mpfr_init2(D,MPFR_PREC_MIN)
#define CGALRS_dyadic_init2(D,P) mpfr_init2(D,P)
#define CGALRS_dyadic_clear(D) mpfr_clear(D)
inline void CGALRS_dyadic_set(CGALRS_dyadic_ptr rop,CGALRS_dyadic_srcptr op){
if(rop!=op){
CGALRS_dyadic_set_prec(rop,mpfr_get_prec(op));
mpfr_set(rop,op,GMP_RNDN);
}
CGAL_assertion(mpfr_equal_p(rop,op)!=0);
}
inline void CGALRS_dyadic_set_z(CGALRS_dyadic_ptr rop,mpz_srcptr z){
size_t prec;
prec=mpz_sizeinbase(z,2)-(mpz_tstbit(z,0)?0:mpz_scan1(z,0));
CGALRS_dyadic_set_prec(rop,prec);
mpfr_set_z(rop,z,GMP_RNDN);
CGAL_assertion(!mpfr_cmp_z(rop,z));
}
inline void CGALRS_dyadic_set_si(CGALRS_dyadic_ptr rop,long s){
CGALRS_dyadic_set_prec(rop,sizeof(long));
mpfr_set_si(rop,s,GMP_RNDN);
CGAL_assertion(!mpfr_cmp_si(rop,s));
}
inline void CGALRS_dyadic_set_ui(CGALRS_dyadic_ptr rop,unsigned long u){
CGALRS_dyadic_set_prec(rop,sizeof(unsigned long));
mpfr_set_ui(rop,u,GMP_RNDN);
CGAL_assertion(!mpfr_cmp_ui(rop,u));
}
inline void CGALRS_dyadic_set_fr(CGALRS_dyadic_ptr rop,mpfr_srcptr op){
if(rop!=op){
CGALRS_dyadic_set_prec(rop,mpfr_get_prec(op));
mpfr_set(rop,op,GMP_RNDN);
CGAL_assertion(mpfr_equal_p(rop,op)!=0);
}
}
#define CGALRS_dyadic_init_set(R,D) \
( CGALRS_dyadic_init(R), CGALRS_dyadic_set((R), (D)) )
#define CGALRS_dyadic_init_set_z(R,Z) \
( CGALRS_dyadic_init(R), CGALRS_dyadic_set_z((R), (Z)) )
#define CGALRS_dyadic_init_set_si(R,I) \
( CGALRS_dyadic_init(R), CGALRS_dyadic_set_si((R), (I)) )
#define CGALRS_dyadic_init_set_ui(R,I) \
( CGALRS_dyadic_init(R), CGALRS_dyadic_set_ui((R), (I)) )
#define CGALRS_dyadic_init_set_fr(R,F) \
( CGALRS_dyadic_init(R), CGALRS_dyadic_set_fr((R), (F)) )
#define CGALRS_dyadic_get_fr(M,D) mpfr_set(M,D,GMP_RNDN)
#define CGALRS_dyadic_get_d(D,RM) mpfr_get_d(D,RM)
inline void CGALRS_dyadic_get_exactfr(mpfr_ptr rop,CGALRS_dyadic_srcptr op){
if(rop!=op){
CGALRS_dyadic_set_prec(rop,mpfr_get_prec(op));
mpfr_set(rop,op,GMP_RNDN);
CGAL_assertion(mpfr_equal_p(rop,op)!=0);
}
}
#define CGALRS_dyadic_canonicalize(D) ()
// comparison functions
#define CGALRS_dyadic_sgn(D) mpfr_sgn(D)
#define CGALRS_dyadic_zero(D) mpfr_zero_p(D)
#define CGALRS_dyadic_cmp(D,E) mpfr_cmp(D,E)
// arithmetic functions
#define CGALRS_dyadic_add(R,D,E) CGALRS_dyadic_ll_add(R,D,E,0)
#define CGALRS_dyadic_sub(R,D,E) CGALRS_dyadic_ll_sub(R,D,E,0)
#define CGALRS_dyadic_mul(R,D,E) CGALRS_dyadic_ll_mul(R,D,E,0)
inline void CGALRS_dyadic_neg(CGALRS_dyadic_ptr rop,CGALRS_dyadic_srcptr op){
if(rop!=op)
CGALRS_dyadic_set_prec(rop,mpfr_get_prec(op));
mpfr_neg(rop,op,GMP_RNDN);
CGAL_assertion(
rop==op||
(!mpfr_cmpabs(rop,op)&&
((CGALRS_dyadic_zero(op)&&CGALRS_dyadic_zero(rop))||
(CGALRS_dyadic_sgn(op)!=CGALRS_dyadic_sgn(rop)))));
}
// low-level addition:
// add op1 and op2 and reserve b bits for future lowlevel operations
inline void CGALRS_dyadic_ll_add(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
CGALRS_dyadic_srcptr op2,
mp_prec_t b){
mp_exp_t l,r,temp1,temp2;
mp_prec_t rop_prec;
if(mpfr_zero_p(op1)){
if(rop!=op2)
CGALRS_dyadic_set(rop,op2);
return;
}
if(mpfr_zero_p(op2)){
if(rop!=op1)
CGALRS_dyadic_set(rop,op1);
return;
}
l=mpfr_get_exp(op1)>mpfr_get_exp(op2)?
mpfr_get_exp(op1):
mpfr_get_exp(op2);
temp1=mpfr_get_exp(op1)-(mp_exp_t)mpfr_get_prec(op1);
temp2=mpfr_get_exp(op2)-(mp_exp_t)mpfr_get_prec(op2);
r=temp1>temp2?temp2:temp1;
CGAL_assertion(l>r);
rop_prec=b+1+(mp_prec_t)(l-r);
CGAL_assertion(rop_prec>=mpfr_get_prec(op1)&&
rop_prec>=mpfr_get_prec(op2));
if(rop==op1||rop==op2)
CGALRS_dyadic_prec_round(rop,rop_prec);
else
CGALRS_dyadic_set_prec(rop,rop_prec);
CGAL_assertion_code(int round=)
mpfr_add(rop,op1,op2,GMP_RNDN);
CGAL_assertion(!round);
}
inline void CGALRS_dyadic_add_z(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
mpz_srcptr z){
mp_exp_t l,r;
mp_prec_t rop_prec;
if(mpfr_zero_p(op1)){
CGALRS_dyadic_set_z(rop,z);
return;
}
if(!mpz_sgn(z)){
if(rop!=op1)
CGALRS_dyadic_set(rop,op1);
return;
}
l=mpfr_get_exp(op1)>(mp_exp_t)mpz_sizeinbase(z,2)?
mpfr_get_exp(op1):
mpz_sizeinbase(z,2);
r=mpfr_get_exp(op1)-(mp_exp_t)mpfr_get_prec(op1)<0?
mpfr_get_exp(op1)-(mp_exp_t)mpfr_get_prec(op1):
0;
CGAL_assertion(l>r);
rop_prec=1+(mp_prec_t)(l-r);
CGAL_assertion(rop_prec>=mpfr_get_prec(op1)&&
rop_prec>=(mp_prec_t)mpz_sizeinbase(z,2));
if(rop==op1)
CGALRS_dyadic_prec_round(rop,rop_prec);
else
CGALRS_dyadic_set_prec(rop,rop_prec);
CGAL_assertion_code(int round=)
mpfr_add_z(rop,op1,z,GMP_RNDN);
CGAL_assertion(!round);
}
// low-level subtraction:
// subtract op2 to op1 and reserve b bits for future lowlevel operations
inline void CGALRS_dyadic_ll_sub(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
CGALRS_dyadic_srcptr op2,
mp_prec_t b){
mp_exp_t l,r,temp1,temp2;
mp_prec_t rop_prec;
if(mpfr_zero_p(op1)){
CGALRS_dyadic_neg(rop,op2);
return;
}
if(mpfr_zero_p(op2)){
if(rop!=op1)
CGALRS_dyadic_set(rop,op1);
return;
}
l=mpfr_get_exp(op1)>mpfr_get_exp(op2)?
mpfr_get_exp(op1):
mpfr_get_exp(op2);
temp1=mpfr_get_exp(op1)-(mp_exp_t)mpfr_get_prec(op1);
temp2=mpfr_get_exp(op2)-(mp_exp_t)mpfr_get_prec(op2);
r=temp1>temp2?temp2:temp1;
CGAL_assertion(l>r);
rop_prec=b+1+(mp_prec_t)(l-r);
CGAL_assertion(rop_prec>=mpfr_get_prec(op1)&&
rop_prec>=mpfr_get_prec(op2));
if(rop==op1||rop==op2)
CGALRS_dyadic_prec_round(rop,rop_prec);
else
CGALRS_dyadic_set_prec(rop,rop_prec);
CGAL_assertion_code(int round=)
mpfr_sub(rop,op1,op2,GMP_RNDN);
CGAL_assertion(!round);
}
// low-level multiplication:
// multiply op1 and op2 and reserve b bits for future lowlevel operations
inline void CGALRS_dyadic_ll_mul(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
CGALRS_dyadic_srcptr op2,
mp_prec_t b){
if(rop==op1||rop==op2)
CGALRS_dyadic_prec_round(rop,b+mpfr_get_prec(op1)+mpfr_get_prec(op2));
else
CGALRS_dyadic_set_prec(rop,b+mpfr_get_prec(op1)+mpfr_get_prec(op2));
CGAL_assertion_code(int round=)
mpfr_mul(rop,op1,op2,GMP_RNDN);
CGAL_assertion(!round);
}
inline void CGALRS_dyadic_mul_z(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
mpz_srcptr z){
if(rop==op1)
CGALRS_dyadic_prec_round(
rop,
mpfr_get_prec(op1)+mpz_sizeinbase(z,2));
else
CGALRS_dyadic_set_prec(
rop,
mpfr_get_prec(op1)+mpz_sizeinbase(z,2));
CGAL_assertion_code(int round=)
mpfr_mul_z(rop,op1,z,GMP_RNDN);
CGAL_assertion(!round);
}
inline void CGALRS_dyadic_mul_si(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
long s){
if(rop==op1)
CGALRS_dyadic_prec_round(rop,mpfr_get_prec(op1)+sizeof(long));
else
CGALRS_dyadic_set_prec(rop,mpfr_get_prec(op1)+sizeof(long));
CGAL_assertion_code(int round=)
mpfr_mul_si(rop,op1,s,GMP_RNDN);
CGAL_assertion(!round);
}
inline void CGALRS_dyadic_mul_ui(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
unsigned long u){
if(rop==op1)
CGALRS_dyadic_prec_round(
rop,
mpfr_get_prec(op1)+sizeof(unsigned long));
else
CGALRS_dyadic_set_prec(
rop,
mpfr_get_prec(op1)+sizeof(unsigned long));
CGAL_assertion_code(int round=)
mpfr_mul_ui(rop,op1,u,GMP_RNDN);
CGAL_assertion(!round);
}
inline void CGALRS_dyadic_pow_ui(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
unsigned long u){
if(!u){
CGAL_assertion_msg(!mpfr_zero_p(op1),"0^0");
CGALRS_dyadic_set_ui(rop,1);
return;
}
if(u==1){
if(rop!=op1)
CGALRS_dyadic_set(rop,op1);
return;
}
if(mpfr_zero_p(op1)){
CGAL_assertion_msg(u!=0,"0^0");
CGALRS_dyadic_set_ui(rop,0);
return;
}
if(!mpfr_cmp_ui(op1,1)){
if(rop!=op1)
CGALRS_dyadic_set(rop,op1);
return;
}
if(rop==op1)
CGALRS_dyadic_prec_round(rop,u*mpfr_get_prec(op1));
else
CGALRS_dyadic_set_prec(rop,u*mpfr_get_prec(op1));
CGAL_assertion_code(int round=)
mpfr_pow_ui(rop,op1,u,GMP_RNDN);
CGAL_assertion(!round);
}
inline void CGALRS_dyadic_addmul(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
CGALRS_dyadic_srcptr op2){
CGALRS_dyadic_t temp;
CGALRS_dyadic_init(temp);
CGALRS_dyadic_mul(temp,op1,op2);
CGALRS_dyadic_add(rop,rop,temp);
CGALRS_dyadic_clear(temp);
}
inline void CGALRS_dyadic_addmul_si(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
long op2){
CGALRS_dyadic_t temp;
CGALRS_dyadic_init(temp);
CGALRS_dyadic_mul_si(temp,op1,op2);
CGALRS_dyadic_add(rop,rop,temp);
CGALRS_dyadic_clear(temp);
}
inline void CGALRS_dyadic_addmul_ui(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
unsigned long u){
//CGALRS_dyadic_t temp;
//CGALRS_dyadic_init(temp);
//CGALRS_dyadic_mul_ui(temp,op1,u);
//CGALRS_dyadic_add(rop,rop,temp);
//CGALRS_dyadic_clear(temp);
CGALRS_dyadic_t temp;
mp_exp_t l,r,temp1,temp2;
mp_prec_t rop_prec;
if(u==0||mpfr_zero_p(op1))
return;
if(u==1){
CGALRS_dyadic_add(rop,rop,op1);
return;
}
// TODO: if(op1==1)
// calculate temp=op1*u
mpfr_init2(temp,mpfr_get_prec(op1)+sizeof(unsigned int));
CGAL_assertion_code(int round1=)
mpfr_mul_ui(temp,op1,u,GMP_RNDN);
CGAL_assertion(!round1);
// calculate the precision needed for rop
l=mpfr_get_exp(op1)>0?mpfr_get_exp(op1):0;
temp1=mpfr_get_exp(op1)-(mp_exp_t)mpfr_get_prec(op1);
temp2=sizeof(unsigned long);
r=temp1>temp2?temp2:temp1;
CGAL_assertion(l>r);
rop_prec=sizeof(unsigned long)+1+(mp_prec_t)(l-r);
CGAL_assertion(rop_prec>=mpfr_get_prec(op1)&&
rop_prec>=mpfr_get_prec(rop));
// set precision and add
CGALRS_dyadic_prec_round(rop,rop_prec);
CGAL_assertion_code(int round2=)
mpfr_add(rop,rop,temp,GMP_RNDN);
CGAL_assertion(!round2);
}
inline void CGALRS_dyadic_mul_2exp(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
unsigned long ui){
// mpfr_mul_2ui does change the mantissa!
if(rop==op1)
CGALRS_dyadic_prec_round(
rop,
sizeof(unsigned long)+mpfr_get_prec(op1));
else
CGALRS_dyadic_set_prec(
rop,
sizeof(unsigned long)+mpfr_get_prec(op1));
CGAL_assertion_code(int round=)
mpfr_mul_2ui(rop,op1,ui,GMP_RNDN);
CGAL_assertion(!round);
}
inline void CGALRS_dyadic_div_2exp(CGALRS_dyadic_ptr rop,
CGALRS_dyadic_srcptr op1,
unsigned long ui){
// mpfr_div_2ui does not change the mantissa... am I sure?
CGAL_assertion_code(int round=)
mpfr_div_2ui(rop,op1,ui,GMP_RNDN);
CGAL_assertion(!round);
}
// miscellaneous functions
#define CGALRS_dyadic_midpoint(R,D,E) \
( CGALRS_dyadic_ll_add(R,D,E,1) , mpfr_div_2ui(R,R,1,GMP_RNDN) )
#define CGALRS_dyadic_swap(D,E) mpfr_swap(D,E)
// I/O functions
#define CGALRS_dyadic_out_str(F,D) mpfr_out_str(F,10,0,D,GMP_RNDN)
#ifdef __cplusplus
inline std::ostream& operator<<(std::ostream &s,CGALRS_dyadic_srcptr op){
mp_exp_t exponent;
mpz_t mantissa;
mpz_init(mantissa);
exponent=mpfr_get_z_exp(mantissa,op);
s<<"["<<mantissa<<","<<exponent<<"]";
return s;
}
#endif
#endif // CGAL_RS_DYADIC_H