summaryrefslogtreecommitdiff
path: root/utils/ftoa.h
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ftoa.h')
-rw-r--r--utils/ftoa.h403
1 files changed, 0 insertions, 403 deletions
diff --git a/utils/ftoa.h b/utils/ftoa.h
deleted file mode 100644
index 3dba528d..00000000
--- a/utils/ftoa.h
+++ /dev/null
@@ -1,403 +0,0 @@
-#ifndef FTOA_H
-#define FTOA_H
-
-
-//TODO: for fractional digits/non-sci, determine the right amount of left padding (more if the whole number is indeed <1, to keep the significant digits), less if sci notation and/or mantissa has sig. digits (don't want N before . and N after!)
-
-#ifndef FTOA_ROUNDTRIP
-# define FTOA_ROUNDTRIP 1
-#endif
-
-#ifndef FTOA_DEBUG
-# define FTOA_DEBUG 0
-#endif
-
-#ifndef FTOA_USE_SPRINTF
-#define FTOA_USE_SPRINTF 0
-#endif
-
-#if FTOA_DEBUG
-# define FTOAassert(x) assert(x)
-# define DBFTOA(x) std::cerr<<"\nFTOA " <<__func__<<"("<<__LINE__<<"): " #x "="<<x<<"\n"
-# define DBFTOA2(x0,x1) std::cerr<<"\nFTOA " <<__func__<<"("<<__LINE__<<"): " #x0 "="<<x0<<" " #x1 "="<<x1 <<"\n"
-#else
-# define FTOAassert(x)
-# define DBFTOA(x)
-# define DBFTOA2(x0,x1)
-#endif
-
-/* DECIMAL_FOR_WHOLE ; ftos(123)
- 0 ; 123
- 1 ; 123
- 2 ; 123.
- ; ftos(0) is always just "0" (not "0.0")
- ; ftos(.01)
- 0 ; .01
- 1 ; 0.01
- 2 ; 0.01
-
-*/
-
-#ifndef DECIMAL_FOR_WHOLE
-# define DECIMAL_FOR_WHOLE 1
-#endif
-
-#include <limits>
-#include <stdint.h>
-#include <iostream>
-#include <cmath>
-#include <assert.h>
-#include <cstdio>
-#include "utoa.h"
-#include "nan.h"
-
-template <class Float>
-struct ftoa_traits {
-};
-
-//eP10,
-// sigd decimal places normally printed, roundtripd needed so that round-trip float->string->float is identity
-
-#define DEFINE_FTOA_TRAITS(FLOATT,INTT,sigd,roundtripd,small,large,used,P10) \
-template <> \
-struct ftoa_traits<FLOATT> { \
- typedef INTT int_t; \
- typedef u ## INTT uint_t; \
- typedef FLOATT float_t; \
- enum { digits10=std::numeric_limits<INTT>::digits10, chars_block=P10, usedig=used, sigdig=sigd, roundtripdig=roundtripd, bufsize=roundtripdig+7 }; \
- static const double pow10_block = 1e ## P10; \
- static const float_t small_f = small; \
- static const float_t large_f = large; \
- static inline int sprintf(char *buf,double f) { return std::sprintf(buf,"%." #used "g",f); } \
- static inline int sprintf_sci(char *buf,double f) { return std::sprintf(buf,"%." #used "e",f); } \
- static inline int sprintf_nonsci(char *buf,double f) { return std::sprintf(buf,"%." #used "f",f); } \
- static inline uint_t fracblock(double frac) { FTOAassert(frac>=0 && frac<1); double f=frac*pow10_block;uint_t i=(uint_t)f;FTOAassert(i<pow10_block);return i; } \
- static inline uint_t rounded_fracblock(double frac) { FTOAassert(frac>=0 && frac<1); double f=frac*pow10_block;uint_t i=(uint_t)(f+.5);FTOAassert(i<pow10_block);return i; } \
- static inline float_t mantexp10(float_t f,int &exp) { float_t e=std::log10(f); float_t ef=std::floor(e); exp=ef; return f/std::pow((float_t)10,ef); } \
- static inline bool use_sci_abs(float_t fa) { return fa<small || fa>large; } \
- static inline bool use_sci(float_t f) { return use_sci_abs(std::fabs(f)); } \
-};
-//TODO: decide on computations in double (would hurt long double) or in native float type - any advantage? more precision is usually better.
-
-//10^22 = 0x1.0f0cf064dd592p73 is the largest exactly representable power of 10 in the binary64 format. but round down to 18 so int64_t can hold it.
-
-#if FTOA_ROUNDTRIP
-#define DEFINE_FTOA_TRAITS_ROUNDTRIP(FLOATT,INTT,sigd,roundtripd,small,large) DEFINE_FTOA_TRAITS(FLOATT,INTT,sigd,roundtripd,small,large,roundtripd,roundtripd)
-#else
-#define DEFINE_FTOA_TRAITS_ROUNDTRIP(FLOATT,INTT,sigd,roundtripd,small,large) DEFINE_FTOA_TRAITS(FLOATT,INTT,sigd,roundtripd,small,large,sigd,sigd)
-#endif
-
-DEFINE_FTOA_TRAITS_ROUNDTRIP(double,int64_t,15,17,1e-5,1e8)
-//i've heard that 1e10 is fine for float. but we only have 1e9 (9 decimal places) in int32.
-DEFINE_FTOA_TRAITS_ROUNDTRIP(float,int32_t,6,9,1e-3,1e8)
-
-
-template <class F>
-inline void ftoa_error(F f,char const* msg="") {
- using namespace std;
- cerr<<"ftoa error: "<<msg<<" f="<<f<<endl;
- assert(!"ftoa error");
-}
-
-// all of the below prepend and return new cursor. null terminate yourself (like itoa/utoa)
-
-//possibly empty string for ~0 (no sci notation fallback). left padded with the right number of 0s (tricky). [ret,p) are the digits.
-template <class F>
-char *prepend_pos_frac_digits(char *p,F f) {
- FTOAassert(f<1 && f >0);
- typedef ftoa_traits<F> FT;
- //repeat if very small??? nah, require sci notation to take care of it.
- typename FT::uint_t i=FT::rounded_fracblock(f);
- DBFTOA2(f,i);
- if (i>0) {
- unsigned n_skipped;
- char *d=utoa_drop_trailing_0(p,i,n_skipped);
- char *b=p-FT::chars_block+n_skipped;
- FTOAassert(b<=d);
- left_pad(b,d,'0');
- return b;
- } else {
- return p;
- }
-}
-
-template <class F>
-char *append_pos_frac_digits(char *p,F f) { // '0' right-padded, nul terminated, return position of nul. [p,ret) are the digits
- if (f==0) {
- *p++='0';
- return p;
- }
- FTOAassert(f<1 && f >0);
- typedef ftoa_traits<F> FT;
- //repeat if very small??? nah, require sci notation to take care of it.
- typename FT::uint_t i=FT::rounded_fracblock(f);
- DBFTOA2(f,i);
- if (i>0) {
- char *e=p+FT::chars_block;
- utoa_left_pad(p,e,i,'0');
- *e=0;
- return e;
- } else {
- *p=0;
- return p;
- }
-}
-
-template <class F>
-inline char *prepend_pos_frac(char *p,F f) {
- FTOAassert(f<1 && f>=0);
- if (f==0) {
- *--p='0';
- return p;
- }
- p=prepend_pos_frac_digits(p,f);
- *--p='.';
- if (DECIMAL_FOR_WHOLE>0)
- *--p='0';
- return p;
-}
-
-template <class F>
-inline char *append_pos_frac(char *p,F f) {
- DBFTOA(f);
- if (DECIMAL_FOR_WHOLE>0)
- *p++='0';
- *p++='.';
- return append_pos_frac_digits(p,f);
-}
-
-template <class F>
-inline char *prepend_frac(char *p,F f,bool positive_sign=false) {
- FTOAassert(f<1 && f>-1);
- if (f==0)
- *--p='0';
- else if (f<0) {
- p=prepend_pos_frac(p,-f);
- *--p='-';
- } else {
- p=prepend_pos_frac(p,f);
- if (positive_sign)
- *--p='+';
- }
- return p;
-}
-
-
-template <class F>
-inline char *append_sign(char *p,F f,bool positive_sign=false) {
- if (f<0) {
- *p++='-';
- } else if (positive_sign)
- *p++='+';
- return p;
-}
-
-template <class F>
-inline char *append_frac(char *p,F f,bool positive_sign=false) {
- FTOAassert(f<1 && f>-1);
- if (f==0) {
- *p++='0';
- return p;
- } else if (f<0) {
- *p++='-';
- return append_pos_frac(p,-f);
- }
- if (positive_sign) {
- *p++='+';
- return append_pos_frac(p,f);
- }
-
-}
-
-
-//append_frac, append_pos_sci, append_sci. notice these are all composed according to a pattern (but reversing order of composition in pre vs app). or can implement with copy through buffer
-
-/* will switch to sci notation if integer part is too big for the int type. but for very small values, will simply display 0 (i.e. //TODO: find out log10 and leftpad 0s then convert rest) */
-template <class F>
-char *prepend_pos_nonsci(char *p,F f) {
- typedef ftoa_traits<F> FT;
- typedef typename FT::uint_t uint_t;
- DBFTOA(f);
- FTOAassert(f>0);
- if (f>std::numeric_limits<uint_t>::max())
- return prepend_pos_sci(p,f);
- //which is faster - modf is weird and returns negative frac part if f is negative. while we could deal with this using fabs, we instead only handle positive here (put - sign in front and negate, then call us) - ?
-#if 0
- F intpart;
- F frac=std::modf(f,&intpart);
- uint_t u=intpart;
-#else
- uint_t u=f;
- F frac=f-u;
-#endif
- DBFTOA2(u,frac);
- if (frac == 0) {
- if (DECIMAL_FOR_WHOLE>1)
- *--p='.';
- } else {
- p=prepend_pos_frac_digits(p,frac);
- *--p='.';
- }
- if (u==0) {
- if (DECIMAL_FOR_WHOLE>0)
- *--p='0';
- } else
- p=utoa(p,u);
- return p;
-}
-
-// modify p; return true if handled
-template <class F>
-inline bool prepend_0_etc(char *&p,F f,bool positive_sign=false) {
- if (f==0) {
- *--p='0';
- return true;
- }
- if (is_nan(f)) {
- p-=3;
- p[0]='N';p[1]='A';p[2]='N';
- return true;
- }
- if (is_pos_inf(f)) {
- p-=3;
- p[0]='I';p[1]='N';p[2]='F';
- if (positive_sign)
- *--p='+';
- return true;
- }
- if (is_neg_inf(f)) {
- p-=4;
- p[0]='-';p[1]='I';p[2]='N';p[3]='F';
- return true;
- }
- return false;
-}
-
-template <class F>
-inline char *prepend_nonsci(char *p,F f,bool positive_sign=false) {
- if (prepend_0_etc(p,f,positive_sign)) return p;
- if (f<0) {
- p=prepend_pos_nonsci(p,-f);
- *--p='-';
- } else {
- p=prepend_pos_nonsci(p,f);
- if (positive_sign)
- *--p='+';
- }
- return p;
-}
-
-template <class F>
-inline char *prepend_pos_sci(char *p,F f,bool positive_sign_exp=false) {
- FTOAassert(f>0);
- typedef ftoa_traits<F> FT;
- int e10;
- F mant=FT::mantexp10(f,e10);
- DBFTOA(f);
- DBFTOA2(mant,e10);
- FTOAassert(mant<10.00001);
- if (mant>=10.) {
- ++e10;
- mant*=.1;
- } else if (mant < 1.) {
- --e10;
- mant*=10;
- }
- p=itoa(p,e10,positive_sign_exp);
- *--p='e';
- return prepend_pos_nonsci(p,mant);
-}
-
-template <class F>
-inline char *prepend_sci(char *p,F f,bool positive_sign_mant=false,bool positive_sign_exp=false) {
- if (prepend_0_etc(p,f,positive_sign_mant)) return p;
- if (f==0)
- *--p='0';
- else if (f<0) {
- p=prepend_pos_sci(p,-f,positive_sign_exp);
- *--p='-';
- } else {
- p=prepend_pos_sci(p,f,positive_sign_exp);
- if (positive_sign_mant)
- *--p='+';
- }
- return p;
-}
-
-template <class F>
-inline char *append_nonsci(char *p,F f,bool positive_sign=false) {
- if (positive_sign&&f>=0) *p++='+';
- return p+ftoa_traits<F>::sprintf_nonsci(p,f);
-}
-
-template <class F>
-inline char *append_sci(char *p,F f,bool positive_sign=false) {
- if (positive_sign&&f>=0) *p++='+';
- return p+ftoa_traits<F>::sprintf_sci(p,f);
-}
-
-template <class F>
-inline char *append_ftoa(char *p,F f,bool positive_sign=false) {
- if (positive_sign&&f>=0) *p++='+';
- return p+ftoa_traits<F>::sprintf(p,f);
-}
-
-template <class F>
-inline char *prepend_ftoa(char *p,F f)
-{
- typedef ftoa_traits<F> FT;
- return FT::use_sci(f) ? prepend_sci(p,f) : prepend_nonsci(p,f);
-}
-
-template <class F>
-inline std::string ftos_append(F f) {
- typedef ftoa_traits<F> FT;
- char buf[FT::bufsize];
- return std::string(buf,append_ftoa(buf,f));
-}
-
-template <class F>
-inline std::string ftos_prepend(F f) {
- typedef ftoa_traits<F> FT;
- char buf[FT::bufsize];
- char *end=buf+FT::bufsize;
- return std::string(prepend_ftoa(end,f),end);
-}
-
-
-template <class F>
-inline std::string ftos(F f) {
-#if 0
- // trust RVO? no extra copies?
- return FTOA_USE_SPRINTF ? ftos_append(f) : ftos_prepend(f);
-#else
- typedef ftoa_traits<F> FT;
- char buf[FT::bufsize];
- if (FTOA_USE_SPRINTF) {
- return std::string(buf,append_ftoa(buf,f));
- } else {
- char *end=buf+FT::bufsize;
- return std::string(prepend_ftoa(end,f),end);
- }
-#endif
-}
-
-namespace {
- const int ftoa_bufsize=30;
- char ftoa_outbuf[ftoa_bufsize];
-}
-
-// not even THREADLOCAL - don't use.
-inline char *static_ftoa(float f)
-{
- if (FTOA_USE_SPRINTF) {
- append_ftoa(ftoa_outbuf,f);
- return ftoa_outbuf;
- } else {
- char *end=ftoa_outbuf+ftoa_bufsize;
- return prepend_ftoa(end,f);
- }
-}
-
-
-#endif