fast_output.h
Go to the documentation of this file.
00001 /*
00002  * Copyright 2005, 2006, 2007
00003  * Nick Galbreath -- nickg [at] modp [dot] com
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are
00008  * met:
00009  *
00010  *   Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  *
00013  *   Redistributions in binary form must reproduce the above copyright
00014  *   notice, this list of conditions and the following disclaimer in the
00015  *   documentation and/or other materials provided with the distribution.
00016  *
00017  *   Neither the name of the modp.com nor the names of its
00018  *   contributors may be used to endorse or promote products derived from
00019  *   this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00024  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00025  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00026  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00027  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00028  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00029  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00030  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00031  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032  *
00033  * This is the standard "new" BSD license:
00034  * http://www.opensource.org/licenses/bsd-license.php
00035  */
00036 
00037 #ifndef FAST_OUTPUT_H
00038 #define FAST_OUTPUT_H
00039 
00040 #include <cstdio>
00041 #include <stdint.h>
00042 #include <assert.h>
00043 
00044 #ifdef __cplusplus
00045 extern "C" {
00046 #endif
00047 
00048 inline void strreverse(char* begin, char* end)
00049 {
00050   char aux;
00051   while (end > begin)
00052     aux = *end, *end-- = *begin, *begin++ = aux;
00053 }
00054 
00055 inline int modp_dtoa(double value, char* str, int prec)
00056 {
00057   static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
00058 
00059   /* Hacky test for NaN
00060    * under -fast-math this won't work, but then you also won't
00061    * have correct nan values anyways.  The alternative is
00062    * to link with libmath (bad) or hack IEEE double bits (bad)
00063    */
00064   if (! (value == value)) {
00065     str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
00066     assert(0);
00067     return 3;
00068   }
00069   /* if input is larger than thres_max, revert to exponential */
00070   const double thres_max = (double)(0x7FFFFFFF);
00071 
00072   double diff = 0.0;
00073   char* wstr = str;
00074 
00075   if (prec < 0) {
00076     prec = 0;
00077   } else if (prec > 9) {
00078     /* precision of >= 10 can lead to overflow errors */
00079     prec = 9;
00080   }
00081 
00082 
00083   /* we'll work in positive values and deal with the
00084      negative sign issue later */
00085   int neg = 0;
00086   if (value < 0) {
00087     neg = 1;
00088     value = -value;
00089   }
00090 
00091 
00092   int whole = (int) value;
00093   double tmp = (value - whole) * pow10[prec];
00094   uint32_t frac = (uint32_t)(tmp);
00095   diff = tmp - frac;
00096 
00097   if (diff > 0.5) {
00098     ++frac;
00099     /* handle rollover, e.g.  case 0.99 with prec 1 is 1.0  */
00100     if (frac >= pow10[prec]) {
00101       frac = 0;
00102       ++whole;
00103     }
00104   } else if (diff == 0.5 && ((frac == 0) || (frac & 1))) {
00105     /* if halfway, round up if odd, OR
00106        if last digit is 0.  That last part is strange */
00107     ++frac;
00108   }
00109 
00110   /* for very large numbers switch back to native sprintf for exponentials.
00111      anyone want to write code to replace this? */
00112   /*
00113      normal printf behavior is to print EVERY whole number digit
00114      which can be 100s of characters overflowing your buffers == bad
00115      */
00116   if (value > thres_max) {
00117     return sprintf(str, "%e", neg ? -value : value);
00118   }
00119 
00120   if (prec == 0) {
00121     diff = value - whole;
00122     if (diff > 0.5) {
00123       /* greater than 0.5, round up, e.g. 1.6 -> 2 */
00124       ++whole;
00125     } else if (diff == 0.5 && (whole & 1)) {
00126       /* exactly 0.5 and ODD, then round up */
00127       /* 1.5 -> 2, but 2.5 -> 2 */
00128       ++whole;
00129     }
00130   } else {
00131     int count = prec;
00132     // now do fractional part, as an unsigned number
00133     do {
00134       --count;
00135       *wstr++ = (char)(48 + (frac % 10));
00136     } while (frac /= 10);
00137     // add extra 0s
00138     while (count-- > 0) *wstr++ = '0';
00139     // add decimal
00140     *wstr++ = '.';
00141   }
00142 
00143   // do whole part
00144   // Take care of sign
00145   // Conversion. Number is reversed.
00146   do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
00147   if (neg) {
00148     *wstr++ = '-';
00149   }
00150   //*wstr='\0';
00151   strreverse(str, wstr-1);
00152   return wstr - str;
00153 }
00154 
00155 inline int modp_uitoa10(uint32_t value, char* str)
00156 {
00157   char* wstr=str;
00158   // Conversion. Number is reversed.
00159   do *wstr++ = (char)(48 + (value % 10)); while (value /= 10);
00160   //*wstr='\0';
00161   // Reverse string
00162   strreverse(str, wstr-1);
00163   return wstr - str;
00164 }
00165 
00166 inline int modp_itoa10(int32_t value, char* str)
00167 {
00168   char* wstr=str;
00169   // Take care of sign
00170   unsigned int uvalue = (value < 0) ? -value : value;
00171   // Conversion. Number is reversed.
00172   do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
00173   if (value < 0) *wstr++ = '-';
00174   *wstr='\0';
00175 
00176   // Reverse string
00177   strreverse(str,wstr-1);
00178   return wstr - str;
00179 }
00180 
00181 #ifdef __cplusplus
00182 }
00183 #endif
00184 
00185 #endif


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:31:08