g2o
fast_output.h
Go to the documentation of this file.
1 /*
2  * Copyright 2005, 2006, 2007
3  * Nick Galbreath -- nickg [at] modp [dot] com
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * Neither the name of the modp.com nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * This is the standard "new" BSD license:
34  * http://www.opensource.org/licenses/bsd-license.php
35  */
36 
37 #ifndef G2O_FAST_OUTPUT_H
38 #define G2O_FAST_OUTPUT_H
39 
40 #include <cstdio>
41 #include <stdint.h>
42 #include <assert.h>
43 
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47 
48 inline void strreverse(char* begin, char* end)
49 {
50  char aux;
51  while (end > begin)
52  aux = *end, *end-- = *begin, *begin++ = aux;
53 }
54 
55 inline int modp_dtoa(double value, char* str, int prec)
56 {
57  static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
58 
59  /* Hacky test for NaN
60  * under -fast-math this won't work, but then you also won't
61  * have correct nan values anyways. The alternative is
62  * to link with libmath (bad) or hack IEEE double bits (bad)
63  */
64  if (! (value == value)) {
65  str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
66  assert(0);
67  return 3;
68  }
69  /* if input is larger than thres_max, revert to exponential */
70  const double thres_max = (double)(0x7FFFFFFF);
71 
72  double diff = 0.0;
73  char* wstr = str;
74 
75  if (prec < 0) {
76  prec = 0;
77  } else if (prec > 9) {
78  /* precision of >= 10 can lead to overflow errors */
79  prec = 9;
80  }
81 
82 
83  /* we'll work in positive values and deal with the
84  negative sign issue later */
85  int neg = 0;
86  if (value < 0) {
87  neg = 1;
88  value = -value;
89  }
90 
91 
92  int whole = (int) value;
93  double tmp = (value - whole) * pow10[prec];
94  uint32_t frac = (uint32_t)(tmp);
95  diff = tmp - frac;
96 
97  if (diff > 0.5) {
98  ++frac;
99  /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
100  if (frac >= pow10[prec]) {
101  frac = 0;
102  ++whole;
103  }
104  } else if (diff == 0.5 && ((frac == 0) || (frac & 1))) {
105  /* if halfway, round up if odd, OR
106  if last digit is 0. That last part is strange */
107  ++frac;
108  }
109 
110  /* for very large numbers switch back to native sprintf for exponentials.
111  anyone want to write code to replace this? */
112  /*
113  normal printf behavior is to print EVERY whole number digit
114  which can be 100s of characters overflowing your buffers == bad
115  */
116  if (value > thres_max) {
117  return sprintf(str, "%e", neg ? -value : value);
118  }
119 
120  if (prec == 0) {
121  diff = value - whole;
122  if (diff > 0.5) {
123  /* greater than 0.5, round up, e.g. 1.6 -> 2 */
124  ++whole;
125  } else if (diff == 0.5 && (whole & 1)) {
126  /* exactly 0.5 and ODD, then round up */
127  /* 1.5 -> 2, but 2.5 -> 2 */
128  ++whole;
129  }
130  } else {
131  int count = prec;
132  // now do fractional part, as an unsigned number
133  do {
134  --count;
135  *wstr++ = (char)(48 + (frac % 10));
136  } while (frac /= 10);
137  // add extra 0s
138  while (count-- > 0) *wstr++ = '0';
139  // add decimal
140  *wstr++ = '.';
141  }
142 
143  // do whole part
144  // Take care of sign
145  // Conversion. Number is reversed.
146  do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
147  if (neg) {
148  *wstr++ = '-';
149  }
150  //*wstr='\0';
151  strreverse(str, wstr-1);
152  return wstr - str;
153 }
154 
155 inline int modp_uitoa10(uint32_t value, char* str)
156 {
157  char* wstr=str;
158  // Conversion. Number is reversed.
159  do *wstr++ = (char)(48 + (value % 10)); while (value /= 10);
160  //*wstr='\0';
161  // Reverse string
162  strreverse(str, wstr-1);
163  return wstr - str;
164 }
165 
166 inline int modp_itoa10(int32_t value, char* str)
167 {
168  char* wstr=str;
169  // Take care of sign
170  unsigned int uvalue = (value < 0) ? -value : value;
171  // Conversion. Number is reversed.
172  do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
173  if (value < 0) *wstr++ = '-';
174  *wstr='\0';
175 
176  // Reverse string
177  strreverse(str,wstr-1);
178  return wstr - str;
179 }
180 
181 #ifdef __cplusplus
182 }
183 #endif
184 
185 #endif
int modp_uitoa10(uint32_t value, char *str)
Definition: fast_output.h:155
int modp_itoa10(int32_t value, char *str)
Definition: fast_output.h:166
void strreverse(char *begin, char *end)
Definition: fast_output.h:48
int modp_dtoa(double value, char *str, int prec)
Definition: fast_output.h:55