Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
nf_stringToDoubles.c
Go to the documentation of this file.
1/*
2# <<BEGIN-copyright>>
3# Copyright 2019, Lawrence Livermore National Security, LLC.
4# This file is part of the gidiplus package (https://github.com/LLNL/gidiplus).
5# gidiplus is licensed under the MIT license (see https://opensource.org/licenses/MIT).
6# SPDX-License-Identifier: MIT
7# <<END-copyright>>
8*/
9
10#include <stdlib.h>
11#include <ctype.h>
12
13#include "nf_utilities.h"
14
15#ifdef _WIN32
16#include <float.h>
17#endif
18
19#define numberOfStaticDoubles ( 100 * 1000 )
20
21static double *nfu_stringToListOfDoubles2( statusMessageReporting *smr, char const *str, char sep, int64_t *numberConverted,
22 char **endCharacter, int useSystem_strtod );
23/*
24========================================================================
25*/
26double *nfu_stringToListOfDoubles( statusMessageReporting *smr, char const *str, char sep, int64_t *numberConverted,
27 char **endCharacter, int useSystem_strtod ) {
28
29 if( strchr( "0123456789.+-eE", sep ) != NULL ) {
30 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_badInput, "Invalid sep ='%c'.", sep );
31 return( NULL );
32 }
33
34 *numberConverted = 0;
35 *endCharacter = (char *) str;
36 if( isspace( sep ) ) sep = ' '; /* Make it the space character if any white space as it simplifies logic below. */
37 return( nfu_stringToListOfDoubles2( smr, str, sep, numberConverted, endCharacter, useSystem_strtod ) );
38}
39/*
40========================================================================
41*/
42static double *nfu_stringToListOfDoubles2( statusMessageReporting *smr, char const *str, char sep, int64_t *numberConverted,
43 char **endCharacter, int useSystem_strtod ) {
44
45 int64_t i1, i2, numberConverted_initial = *numberConverted;
46 double *doublePtr = NULL;
47 nfu_status status = nfu_Okay;
48 double (*_strtod)( char const *str, char **endCharacter );
49
50#if NFU_USEHEAP
51 double *staticDoubles = (double *) smr_malloc2( smr, (size_t) numberOfStaticDoubles * sizeof( double ), 0, "staticDoubles" );
52 if( staticDoubles == NULL ) {
54 return( NULL );
55 }
56#else
57 double staticDoubles[numberOfStaticDoubles];
58#endif
59
60 _strtod = useSystem_strtod ? strtod : nf_strtod;
61
62 for( i1 = 0; i1 < numberOfStaticDoubles; i1++, (*numberConverted)++ ) {
63 if( *numberConverted == 0 ) {
64 staticDoubles[i1] = _strtod( str, endCharacter ); }
65 else { /* Check that there is one sep character and allow for arbitrary number of white spaces. */
66 char const *str2 = str;
67
68 while( isspace( *str2 ) ) ++str2; /* Only need to check for white spaces before sep character as strtod will ignore after. */
69 if( sep != ' ' ) {
70 if( *str2 == sep ) {
71 ++str2; }
72 else {
73 str2 = str;
74 }
75 }
76 if( str < str2 ) staticDoubles[i1] = _strtod( str2, endCharacter );
77 if( str2 == (char const *) *endCharacter ) *endCharacter = (char *) str;
78 }
79 if( str == (char const *) *endCharacter ) {
80 int64_t number = *numberConverted;
81 if( *numberConverted == 0 ) number = 1;
82 if( ( doublePtr = (double *) smr_malloc2( smr, (size_t) number * sizeof( double ), 0, "doublePtr" ) ) == NULL ) {
84#if NFU_USEHEAP
85 free( staticDoubles );
86#endif
87 return( NULL );
88 }
89 break;
90 }
91 str = (char const *) *endCharacter;
92 }
93
94 if( ( status == nfu_Okay ) && ( doublePtr == NULL ) )
95 doublePtr = nfu_stringToListOfDoubles2( smr, str, sep, numberConverted, endCharacter, useSystem_strtod );
96 if( doublePtr != NULL ) {
97 double *doublePtr2 = &(doublePtr[numberConverted_initial]);
98 char *end = *endCharacter;
99
100 for( i2 = 0; i2 < i1; i2++, doublePtr2++ ) *doublePtr2 = staticDoubles[i2];
101 while( isspace( *end ) ) ++end;
102 if( *end == 0 ) *endCharacter = end;
103 }
104
105#if NFU_USEHEAP
106 free( staticDoubles );
107#endif
108 return( doublePtr );
109}
110
111#define valid_digit( c ) ( ( c ) >= '0' && ( c ) <= '9')
112/*
113============================================================
114*/
115double nf_strtod( char const *str, char **endCharacter ) {
116
117 *endCharacter = (char *) str;
118 char *ptr = *endCharacter;
119
120 while( isspace( *ptr ) ) ++ptr; /* Skip leading white space, if any. */
121
122 double sign = 1.0; /* Get sign, if any. */
123 if( *ptr == '-' ) {
124 sign = -1.0;
125 ++ptr; }
126 else if( *ptr == '+' ) {
127 ++ptr;
128 }
129
130 double value = 0.0; /* Get digits before decimal point or exponent, if any. */
131 for( ; valid_digit( *ptr ); ++ptr ) value = value * 10.0 + ( *ptr - '0' );
132
133 if( *ptr == '.' ) { /* Get digits after decimal point, if any. */
134 double invPow10 = 0.1;
135 ++ptr;
136 while( valid_digit( *ptr ) ) {
137 value += ( *ptr - '0' ) * invPow10;
138 invPow10 *= 0.1;
139 ++ptr;
140 }
141 }
142
143 if( ( *ptr == 'e' ) || ( *ptr == 'E' ) ) { /* Handle exponent, if any. */
144 int negativeExponent = 0;
145
146 ++ptr; /* Get sign of exponent, if any. */
147 if( *ptr == '-' ) {
148 negativeExponent = 1;
149 ++ptr; }
150 else if( *ptr == '+' ) {
151 ++ptr;
152 }
153
154 unsigned int exponent = 0; /* Get digits of exponent. There must be at least 1. */
155 for( ; valid_digit( *ptr ); ++ptr ) exponent = exponent * 10 + ( *ptr - '0' );
156 if( exponent > 308 ) {
157 return( strtod( str, endCharacter ) );
158 }
159
160 double scale = 1.0; /* Calculate scaling factor. */
161 if( exponent == 0 ) negativeExponent = 0;
162 while( exponent >= 50 ) { scale *= 1E50; exponent -= 50; }
163 while( exponent >= 8 ) { scale *= 1E8; exponent -= 8; }
164 while( exponent > 0 ) { scale *= 10.0; exponent -= 1; }
165
166 if( negativeExponent ) scale = 1.0 / scale;
167 value *= scale;
168 }
169
170 *endCharacter = ptr;
171 return( sign * value );
172}
173/*
174============================================================
175*/
176char *nf_floatToShortestString( double value, int significantDigits, int favorEFormBy, int flags ) {
177
178 int n1, ne, nf, digitsRightOfPeriod_f, exponent;
179 char Str_e[512], Str_f[512], *Str_r = Str_e, Fmt[32], *e1, *e2;
180 const char *sign = "";
181
182 if( flags & nf_floatToShortestString_includeSign ) sign = "+";
183
184 if( !isfinite( value ) ) {
185 sprintf( Fmt, "%%%sf", sign );
186 sprintf( Str_e, Fmt, value );
187 return( strdup( Str_e ) );
188 }
189
190 significantDigits--;
191 if( significantDigits < 0 ) significantDigits = 0;
192 if( significantDigits > 24 ) significantDigits = 24;
193
194 sprintf( Fmt, "%%%s.%de", sign, significantDigits );
195 sprintf( Str_e, Fmt, value );
196
197 e1 = strchr( Str_e, 'e' );
198 if( significantDigits == 0 ) {
199 if( *(e1 - 1) != '.' ) {
200 char *e3;
201
202 e2 = strchr( e1, 0 );
203 e3 = e2 + 1;
204 for( ; e2 != e1; e2--, e3-- ) *e3 = *e2;
205 *(e1++) = '.';
206 }
207 }
208 *e1 = 0;
209 n1 = (int) strlen( Str_e ) - 1;
210 if( flags & nf_floatToShortestString_trimZeros ) while( Str_e[n1] == '0' ) n1--;
212 if( !( flags & nf_floatToShortestString_keepPeriod ) ) if( Str_e[n1] == '.' ) n1--;
213 n1++;
214 Str_e[n1] = 0;
215
216 e1++;
217 exponent = (int) strtol( e1, &e2, 10 );
218 if( exponent != 0 ) { /* If 0, the exponent was "e+00". */
219 for( e1 = Str_e; *e1 != 0; e1++ ) ;
220 sprintf( e1, "e%d", exponent );
221
222 digitsRightOfPeriod_f = significantDigits - exponent;
223 if( ( digitsRightOfPeriod_f > 25 ) || ( exponent > 50 ) ) return( strdup( Str_r ) );
224 if( digitsRightOfPeriod_f < 0 ) digitsRightOfPeriod_f = 0;
225
226 sprintf( Fmt, "%%%s.%df", sign, digitsRightOfPeriod_f );
227 sprintf( Str_f, Fmt, value );
228
229 ne = (int) strlen( Str_e );
230 nf = (int) strlen( Str_f );
231 if( strchr( Str_f, '.' ) != NULL ) { /* '.' in string. */
232 if( flags & nf_floatToShortestString_trimZeros ) while( Str_f[nf-1] == '0' ) nf--;
233 if( Str_f[nf-1] == '.' ) {
234 if( !( flags & nf_floatToShortestString_keepPeriod ) ) nf--;
235 } }
236 else { /* Maybe we want a '.' else it looks like an integer, "12345." vs "12345". */
238 Str_f[nf] = '.';
239 nf++;
240 }
241 }
242 Str_f[nf] = 0;
243
244 if( ( nf + favorEFormBy ) < ne ) Str_r = Str_f;
245 }
246 return( strdup( Str_r ) );
247}
void free(voidpf ptr)
double * nfu_stringToListOfDoubles(statusMessageReporting *smr, char const *str, char sep, int64_t *numberConverted, char **endCharacter, int useSystem_strtod)
#define valid_digit(c)
#define numberOfStaticDoubles
char * nf_floatToShortestString(double value, int significantDigits, int favorEFormBy, int flags)
double nf_strtod(char const *str, char **endCharacter)
#define nf_floatToShortestString_includeSign
@ nfu_Okay
@ nfu_badInput
@ nfu_Error
enum nfu_status_e nfu_status
#define nf_floatToShortestString_trimZeros
int nfu_SMR_libraryID
double nf_strtod(char const *ptr, char **endCharacter)
#define nf_floatToShortestString_keepPeriod
#define smr_setReportError2(smr, libraryID, code, fmt,...)
#define smr_setReportError2p(smr, libraryID, code, fmt)
#define smr_malloc2(smr, size, zero, forItem)