1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 Licensed under the Apache License, Version 2.0 (the "License");
3 you may not use this file except in compliance with the License.
4 You may obtain a copy of the License at
5
6 http://www.apache.org/licenses/LICENSE-2.0
7
8 Unless required by applicable law or agreed to in writing, software
9 distributed under the License is distributed on an "AS IS" BASIS,
10 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 See the License for the specific language governing permissions and
12 limitations under the License.
13 ==============================================================================*/
14
15 #include "tensorflow/core/lib/strings/numbers.h"
16
17 #include <ctype.h>
18 #include <float.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <algorithm>
22 #include <cmath>
23 #include <locale>
24 #include <unordered_map>
25
26 #include "tensorflow/core/lib/strings/stringprintf.h"
27 #include "tensorflow/core/platform/logging.h"
28 #include "tensorflow/core/platform/macros.h"
29 #include "tensorflow/core/platform/types.h"
30
31 namespace tensorflow {
32
33 namespace {
34
35 template <typename T>
locale_independent_strtonum(const char * str,const char ** endptr)36 T locale_independent_strtonum(const char* str, const char** endptr) {
37 static const std::unordered_map<string, T> special_nums = {
38 {"inf", std::numeric_limits<T>::infinity()},
39 {"+inf", std::numeric_limits<T>::infinity()},
40 {"-inf", -std::numeric_limits<T>::infinity()},
41 {"infinity", std::numeric_limits<T>::infinity()},
42 {"+infinity", std::numeric_limits<T>::infinity()},
43 {"-infinity", -std::numeric_limits<T>::infinity()},
44 {"nan", std::numeric_limits<T>::quiet_NaN()},
45 {"+nan", std::numeric_limits<T>::quiet_NaN()},
46 {"-nan", -std::numeric_limits<T>::quiet_NaN()},
47 };
48 std::stringstream s(str);
49
50 // Check if str is one of the special numbers.
51 string special_num_str;
52 s >> special_num_str;
53
54 for (int i = 0; i < special_num_str.length(); ++i) {
55 special_num_str[i] =
56 std::tolower(special_num_str[i], std::locale::classic());
57 }
58
59 auto entry = special_nums.find(special_num_str);
60 if (entry != special_nums.end()) {
61 *endptr = str + (s.eof() ? static_cast<std::iostream::pos_type>(strlen(str))
62 : s.tellg());
63 return entry->second;
64 } else {
65 // Perhaps it's a hex number
66 if (special_num_str.compare(0, 2, "0x") == 0 ||
67 special_num_str.compare(0, 3, "-0x") == 0) {
68 return strtol(str, const_cast<char**>(endptr), 16);
69 }
70 }
71 // Reset the stream
72 s.str(str);
73 s.clear();
74 // Use the "C" locale
75 s.imbue(std::locale::classic());
76
77 T result;
78 s >> result;
79
80 // Set to result to what strto{f,d} functions would have returned. If the
81 // number was outside the range, the stringstream sets the fail flag, but
82 // returns the +/-max() value, whereas strto{f,d} functions return +/-INF.
83 if (s.fail()) {
84 if (result == std::numeric_limits<T>::max() ||
85 result == std::numeric_limits<T>::infinity()) {
86 result = std::numeric_limits<T>::infinity();
87 s.clear(s.rdstate() & ~std::ios::failbit);
88 } else if (result == -std::numeric_limits<T>::max() ||
89 result == -std::numeric_limits<T>::infinity()) {
90 result = -std::numeric_limits<T>::infinity();
91 s.clear(s.rdstate() & ~std::ios::failbit);
92 }
93 }
94
95 if (endptr) {
96 *endptr =
97 str +
98 (s.fail() ? static_cast<std::iostream::pos_type>(0)
99 : (s.eof() ? static_cast<std::iostream::pos_type>(strlen(str))
100 : s.tellg()));
101 }
102 return result;
103 }
104
105 } // namespace
106
107 namespace strings {
108
FastInt32ToBufferLeft(int32 i,char * buffer)109 char* FastInt32ToBufferLeft(int32 i, char* buffer) {
110 uint32 u = i;
111 if (i < 0) {
112 *buffer++ = '-';
113 // We need to do the negation in modular (i.e., "unsigned")
114 // arithmetic; MSVC++ apparently warns for plain "-u", so
115 // we write the equivalent expression "0 - u" instead.
116 u = 0 - u;
117 }
118 return FastUInt32ToBufferLeft(u, buffer);
119 }
120
FastUInt32ToBufferLeft(uint32 i,char * buffer)121 char* FastUInt32ToBufferLeft(uint32 i, char* buffer) {
122 char* start = buffer;
123 do {
124 *buffer++ = ((i % 10) + '0');
125 i /= 10;
126 } while (i > 0);
127 *buffer = 0;
128 std::reverse(start, buffer);
129 return buffer;
130 }
131
FastInt64ToBufferLeft(int64 i,char * buffer)132 char* FastInt64ToBufferLeft(int64 i, char* buffer) {
133 uint64 u = i;
134 if (i < 0) {
135 *buffer++ = '-';
136 u = 0 - u;
137 }
138 return FastUInt64ToBufferLeft(u, buffer);
139 }
140
FastUInt64ToBufferLeft(uint64 i,char * buffer)141 char* FastUInt64ToBufferLeft(uint64 i, char* buffer) {
142 char* start = buffer;
143 do {
144 *buffer++ = ((i % 10) + '0');
145 i /= 10;
146 } while (i > 0);
147 *buffer = 0;
148 std::reverse(start, buffer);
149 return buffer;
150 }
151
152 static const double kDoublePrecisionCheckMax = DBL_MAX / 1.000000000000001;
153
DoubleToBuffer(double value,char * buffer)154 char* DoubleToBuffer(double value, char* buffer) {
155 // DBL_DIG is 15 for IEEE-754 doubles, which are used on almost all
156 // platforms these days. Just in case some system exists where DBL_DIG
157 // is significantly larger -- and risks overflowing our buffer -- we have
158 // this assert.
159 static_assert(DBL_DIG < 20, "DBL_DIG is too big");
160
161 bool full_precision_needed = true;
162 if (std::abs(value) <= kDoublePrecisionCheckMax) {
163 int snprintf_result =
164 snprintf(buffer, kFastToBufferSize, "%.*g", DBL_DIG, value);
165
166 // The snprintf should never overflow because the buffer is significantly
167 // larger than the precision we asked for.
168 DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize);
169
170 full_precision_needed =
171 locale_independent_strtonum<double>(buffer, nullptr) != value;
172 }
173
174 if (full_precision_needed) {
175 int snprintf_result =
176 snprintf(buffer, kFastToBufferSize, "%.*g", DBL_DIG + 2, value);
177
178 // Should never overflow; see above.
179 DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize);
180 }
181 return buffer;
182 }
183
184 namespace {
SafeFirstChar(StringPiece str)185 char SafeFirstChar(StringPiece str) {
186 if (str.empty()) return '\0';
187 return str[0];
188 }
SkipSpaces(StringPiece * str)189 void SkipSpaces(StringPiece* str) {
190 while (isspace(SafeFirstChar(*str))) str->remove_prefix(1);
191 }
192 } // namespace
193
safe_strto64(StringPiece str,int64 * value)194 bool safe_strto64(StringPiece str, int64* value) {
195 SkipSpaces(&str);
196
197 int64 vlimit = kint64max;
198 int sign = 1;
199 if (str.Consume("-")) {
200 sign = -1;
201 // Different limit for positive and negative integers.
202 vlimit = kint64min;
203 }
204
205 if (!isdigit(SafeFirstChar(str))) return false;
206
207 int64 result = 0;
208 if (sign == 1) {
209 do {
210 int digit = SafeFirstChar(str) - '0';
211 if ((vlimit - digit) / 10 < result) {
212 return false;
213 }
214 result = result * 10 + digit;
215 str.remove_prefix(1);
216 } while (isdigit(SafeFirstChar(str)));
217 } else {
218 do {
219 int digit = SafeFirstChar(str) - '0';
220 if ((vlimit + digit) / 10 > result) {
221 return false;
222 }
223 result = result * 10 - digit;
224 str.remove_prefix(1);
225 } while (isdigit(SafeFirstChar(str)));
226 }
227
228 SkipSpaces(&str);
229 if (!str.empty()) return false;
230
231 *value = result;
232 return true;
233 }
234
safe_strtou64(StringPiece str,uint64 * value)235 bool safe_strtou64(StringPiece str, uint64* value) {
236 SkipSpaces(&str);
237 if (!isdigit(SafeFirstChar(str))) return false;
238
239 uint64 result = 0;
240 do {
241 int digit = SafeFirstChar(str) - '0';
242 if ((kuint64max - digit) / 10 < result) {
243 return false;
244 }
245 result = result * 10 + digit;
246 str.remove_prefix(1);
247 } while (isdigit(SafeFirstChar(str)));
248
249 SkipSpaces(&str);
250 if (!str.empty()) return false;
251
252 *value = result;
253 return true;
254 }
255
safe_strto32(StringPiece str,int32 * value)256 bool safe_strto32(StringPiece str, int32* value) {
257 SkipSpaces(&str);
258
259 int64 vmax = kint32max;
260 int sign = 1;
261 if (str.Consume("-")) {
262 sign = -1;
263 // Different max for positive and negative integers.
264 ++vmax;
265 }
266
267 if (!isdigit(SafeFirstChar(str))) return false;
268
269 int64 result = 0;
270 do {
271 result = result * 10 + SafeFirstChar(str) - '0';
272 if (result > vmax) {
273 return false;
274 }
275 str.remove_prefix(1);
276 } while (isdigit(SafeFirstChar(str)));
277
278 SkipSpaces(&str);
279
280 if (!str.empty()) return false;
281
282 *value = static_cast<int32>(result * sign);
283 return true;
284 }
285
safe_strtou32(StringPiece str,uint32 * value)286 bool safe_strtou32(StringPiece str, uint32* value) {
287 SkipSpaces(&str);
288 if (!isdigit(SafeFirstChar(str))) return false;
289
290 int64 result = 0;
291 do {
292 result = result * 10 + SafeFirstChar(str) - '0';
293 if (result > kuint32max) {
294 return false;
295 }
296 str.remove_prefix(1);
297 } while (isdigit(SafeFirstChar(str)));
298
299 SkipSpaces(&str);
300 if (!str.empty()) return false;
301
302 *value = static_cast<uint32>(result);
303 return true;
304 }
305
safe_strtof(const char * str,float * value)306 bool safe_strtof(const char* str, float* value) {
307 const char* endptr;
308 *value = locale_independent_strtonum<float>(str, &endptr);
309 while (isspace(*endptr)) ++endptr;
310 // Ignore range errors from strtod/strtof.
311 // The values it returns on underflow and
312 // overflow are the right fallback in a
313 // robust setting.
314 return *str != '\0' && *endptr == '\0';
315 }
316
safe_strtod(const char * str,double * value)317 bool safe_strtod(const char* str, double* value) {
318 const char* endptr;
319 *value = locale_independent_strtonum<double>(str, &endptr);
320 while (isspace(*endptr)) ++endptr;
321 // Ignore range errors from strtod/strtof.
322 // The values it returns on underflow and
323 // overflow are the right fallback in a
324 // robust setting.
325 return *str != '\0' && *endptr == '\0';
326 }
327
FloatToBuffer(float value,char * buffer)328 char* FloatToBuffer(float value, char* buffer) {
329 // FLT_DIG is 6 for IEEE-754 floats, which are used on almost all
330 // platforms these days. Just in case some system exists where FLT_DIG
331 // is significantly larger -- and risks overflowing our buffer -- we have
332 // this assert.
333 static_assert(FLT_DIG < 10, "FLT_DIG is too big");
334
335 int snprintf_result =
336 snprintf(buffer, kFastToBufferSize, "%.*g", FLT_DIG, value);
337
338 // The snprintf should never overflow because the buffer is significantly
339 // larger than the precision we asked for.
340 DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize);
341
342 float parsed_value;
343 if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) {
344 snprintf_result =
345 snprintf(buffer, kFastToBufferSize, "%.*g", FLT_DIG + 3, value);
346
347 // Should never overflow; see above.
348 DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize);
349 }
350 return buffer;
351 }
352
FpToString(Fprint fp)353 string FpToString(Fprint fp) {
354 char buf[17];
355 snprintf(buf, sizeof(buf), "%016llx", static_cast<uint64>(fp));
356 return string(buf);
357 }
358
StringToFp(const string & s,Fprint * fp)359 bool StringToFp(const string& s, Fprint* fp) {
360 char junk;
361 uint64 result;
362 if (sscanf(s.c_str(), "%llx%c", &result, &junk) == 1) {
363 *fp = result;
364 return true;
365 } else {
366 return false;
367 }
368 }
369
Uint64ToHexString(uint64 v,char * buf)370 StringPiece Uint64ToHexString(uint64 v, char* buf) {
371 static const char* hexdigits = "0123456789abcdef";
372 const int num_byte = 16;
373 buf[num_byte] = '\0';
374 for (int i = num_byte - 1; i >= 0; i--) {
375 buf[i] = hexdigits[v & 0xf];
376 v >>= 4;
377 }
378 return StringPiece(buf, num_byte);
379 }
380
HexStringToUint64(const StringPiece & s,uint64 * result)381 bool HexStringToUint64(const StringPiece& s, uint64* result) {
382 uint64 v = 0;
383 if (s.empty()) {
384 return false;
385 }
386 for (size_t i = 0; i < s.size(); i++) {
387 char c = s[i];
388 if (c >= '0' && c <= '9') {
389 v = (v << 4) + (c - '0');
390 } else if (c >= 'a' && c <= 'f') {
391 v = (v << 4) + 10 + (c - 'a');
392 } else if (c >= 'A' && c <= 'F') {
393 v = (v << 4) + 10 + (c - 'A');
394 } else {
395 return false;
396 }
397 }
398 *result = v;
399 return true;
400 }
401
HumanReadableNum(int64 value)402 string HumanReadableNum(int64 value) {
403 string s;
404 if (value < 0) {
405 s += "-";
406 value = -value;
407 }
408 if (value < 1000) {
409 Appendf(&s, "%lld", value);
410 } else if (value >= static_cast<int64>(1e15)) {
411 // Number bigger than 1E15; use that notation.
412 Appendf(&s, "%0.3G", static_cast<double>(value));
413 } else {
414 static const char units[] = "kMBT";
415 const char* unit = units;
416 while (value >= static_cast<int64>(1000000)) {
417 value /= static_cast<int64>(1000);
418 ++unit;
419 CHECK(unit < units + TF_ARRAYSIZE(units));
420 }
421 Appendf(&s, "%.2f%c", value / 1000.0, *unit);
422 }
423 return s;
424 }
425
HumanReadableNumBytes(int64 num_bytes)426 string HumanReadableNumBytes(int64 num_bytes) {
427 if (num_bytes == kint64min) {
428 // Special case for number with not representable negation.
429 return "-8E";
430 }
431
432 const char* neg_str = (num_bytes < 0) ? "-" : "";
433 if (num_bytes < 0) {
434 num_bytes = -num_bytes;
435 }
436
437 // Special case for bytes.
438 if (num_bytes < 1024) {
439 // No fractions for bytes.
440 char buf[8]; // Longest possible string is '-XXXXB'
441 snprintf(buf, sizeof(buf), "%s%lldB", neg_str,
442 static_cast<int64>(num_bytes));
443 return string(buf);
444 }
445
446 static const char units[] = "KMGTPE"; // int64 only goes up to E.
447 const char* unit = units;
448 while (num_bytes >= static_cast<int64>(1024) * 1024) {
449 num_bytes /= 1024;
450 ++unit;
451 CHECK(unit < units + TF_ARRAYSIZE(units));
452 }
453
454 // We use SI prefixes.
455 char buf[16];
456 snprintf(buf, sizeof(buf), ((*unit == 'K') ? "%s%.1f%ciB" : "%s%.2f%ciB"),
457 neg_str, num_bytes / 1024.0, *unit);
458 return string(buf);
459 }
460
HumanReadableElapsedTime(double seconds)461 string HumanReadableElapsedTime(double seconds) {
462 string human_readable;
463
464 if (seconds < 0) {
465 human_readable = "-";
466 seconds = -seconds;
467 }
468
469 // Start with us and keep going up to years.
470 // The comparisons must account for rounding to prevent the format breaking
471 // the tested condition and returning, e.g., "1e+03 us" instead of "1 ms".
472 const double microseconds = seconds * 1.0e6;
473 if (microseconds < 999.5) {
474 strings::Appendf(&human_readable, "%0.3g us", microseconds);
475 return human_readable;
476 }
477 double milliseconds = seconds * 1e3;
478 if (milliseconds >= .995 && milliseconds < 1) {
479 // Round half to even in Appendf would convert this to 0.999 ms.
480 milliseconds = 1.0;
481 }
482 if (milliseconds < 999.5) {
483 strings::Appendf(&human_readable, "%0.3g ms", milliseconds);
484 return human_readable;
485 }
486 if (seconds < 60.0) {
487 strings::Appendf(&human_readable, "%0.3g s", seconds);
488 return human_readable;
489 }
490 seconds /= 60.0;
491 if (seconds < 60.0) {
492 strings::Appendf(&human_readable, "%0.3g min", seconds);
493 return human_readable;
494 }
495 seconds /= 60.0;
496 if (seconds < 24.0) {
497 strings::Appendf(&human_readable, "%0.3g h", seconds);
498 return human_readable;
499 }
500 seconds /= 24.0;
501 if (seconds < 30.0) {
502 strings::Appendf(&human_readable, "%0.3g days", seconds);
503 return human_readable;
504 }
505 if (seconds < 365.2425) {
506 strings::Appendf(&human_readable, "%0.3g months", seconds / 30.436875);
507 return human_readable;
508 }
509 seconds /= 365.2425;
510 strings::Appendf(&human_readable, "%0.3g years", seconds);
511 return human_readable;
512 }
513
514 } // namespace strings
515 } // namespace tensorflow
516