Daniel Konegen / MNIST_example

Dependencies:   mbed-os

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers debug_log_numbers.cc Source File

debug_log_numbers.cc

00001 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
00002 
00003 Licensed under the Apache License, Version 2.0 (the "License");
00004 you may not use this file except in compliance with the License.
00005 You may obtain a copy of the License at
00006 
00007     http://www.apache.org/licenses/LICENSE-2.0
00008 
00009 Unless required by applicable law or agreed to in writing, software
00010 distributed under the License is distributed on an "AS IS" BASIS,
00011 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 See the License for the specific language governing permissions and
00013 limitations under the License.
00014 ==============================================================================*/
00015 
00016 // Implements debug logging for numbers by converting them into strings and then
00017 // calling the main DebugLog(char*) function. These are separated into a
00018 // different file so that platforms can just implement the string output version
00019 // of DebugLog() and then get the numerical variations without requiring any
00020 // more code.
00021 
00022 #include "tensorflow/lite/experimental/micro/debug_log_numbers.h"
00023 
00024 #include "tensorflow/lite/experimental/micro/debug_log.h"
00025 
00026 namespace {
00027 
00028 // All input buffers to the number conversion functions must be this long.
00029 static const int kFastToBufferSize = 48;
00030 
00031 // Reverses a zero-terminated string in-place.
00032 char* ReverseStringInPlace(char* start, char* end) {
00033   char* p1 = start;
00034   char* p2 = end - 1;
00035   while (p1 < p2) {
00036     char tmp = *p1;
00037     *p1++ = *p2;
00038     *p2-- = tmp;
00039   }
00040   return start;
00041 }
00042 
00043 // Appends a string to a string, in-place. You need to pass in the maximum
00044 // string length as the second argument.
00045 char* StrCatStr(char* main, int main_max_length, const char* to_append) {
00046   char* current = main;
00047   while (*current != 0) {
00048     ++current;
00049   }
00050   char* current_end = main + (main_max_length - 1);
00051   while ((*to_append != 0) && (current < current_end)) {
00052     *current = *to_append;
00053     ++current;
00054     ++to_append;
00055   }
00056   *current = 0;
00057   return current;
00058 }
00059 
00060 // Populates the provided buffer with an ASCII representation of the number.
00061 char* FastUInt32ToBufferLeft(uint32_t i, char* buffer, int base) {
00062   char* start = buffer;
00063   do {
00064     int32_t digit = i % base;
00065     char character;
00066     if (digit < 10) {
00067       character = '0' + digit;
00068     } else {
00069       character = 'a' + (digit - 10);
00070     }
00071     *buffer++ = character;
00072     i /= base;
00073   } while (i > 0);
00074   *buffer = 0;
00075   ReverseStringInPlace(start, buffer);
00076   return buffer;
00077 }
00078 
00079 // Populates the provided buffer with an ASCII representation of the number.
00080 char* FastInt32ToBufferLeft(int32_t i, char* buffer) {
00081   uint32_t u = i;
00082   if (i < 0) {
00083     *buffer++ = '-';
00084     u = -u;
00085   }
00086   return FastUInt32ToBufferLeft(u, buffer, 10);
00087 }
00088 
00089 // Converts a number to a string and appends it to another.
00090 char* StrCatInt32(char* main, int main_max_length, int32_t number) {
00091   char number_string[kFastToBufferSize];
00092   FastInt32ToBufferLeft(number, number_string);
00093   return StrCatStr(main, main_max_length, number_string);
00094 }
00095 
00096 // Converts a number to a string and appends it to another.
00097 char* StrCatUInt32(char* main, int main_max_length, uint32_t number, int base) {
00098   char number_string[kFastToBufferSize];
00099   FastUInt32ToBufferLeft(number, number_string, base);
00100   return StrCatStr(main, main_max_length, number_string);
00101 }
00102 
00103 // Populates the provided buffer with ASCII representation of the float number.
00104 // Avoids the use of any floating point instructions (since these aren't
00105 // supported on many microcontrollers) and as a consequence prints values with
00106 // power-of-two exponents.
00107 char* FastFloatToBufferLeft(float f, char* buffer) {
00108   char* current = buffer;
00109   char* current_end = buffer + (kFastToBufferSize - 1);
00110   // Access the bit fields of the floating point value to avoid requiring any
00111   // float instructions. These constants are derived from IEEE 754.
00112   const uint32_t sign_mask = 0x80000000;
00113   const uint32_t exponent_mask = 0x7f800000;
00114   const int32_t exponent_shift = 23;
00115   const int32_t exponent_bias = 127;
00116   const uint32_t fraction_mask = 0x007fffff;
00117   const uint32_t u = *reinterpret_cast<uint32_t*>(&f);
00118   const int32_t exponent =
00119       ((u & exponent_mask) >> exponent_shift) - exponent_bias;
00120   const uint32_t fraction = (u & fraction_mask);
00121   // Expect ~0x2B1B9D3 for fraction.
00122   if (u & sign_mask) {
00123     *current = '-';
00124     current += 1;
00125   }
00126   *current = 0;
00127   // These are special cases for infinities and not-a-numbers.
00128   if (exponent == 128) {
00129     if (fraction == 0) {
00130       current = StrCatStr(current, (current_end - current), "Inf");
00131       return current;
00132     } else {
00133       current = StrCatStr(current, (current_end - current), "NaN");
00134       return current;
00135     }
00136   }
00137   // 0x007fffff (8388607) represents 0.99... for the fraction, so to print the
00138   // correct decimal digits we need to scale our value before passing it to the
00139   // conversion function. This scale should be 10000000/8388608 = 1.1920928955.
00140   // We can approximate this using multiply-adds and right-shifts using the
00141   // values in this array. The 1. portion of the number string is printed out
00142   // in a fixed way before the fraction, below.
00143   const int32_t scale_shifts_size = 13;
00144   const int8_t scale_shifts[13] = {3,  4,  8,  11, 13, 14, 17,
00145                                    18, 19, 20, 21, 22, 23};
00146   uint32_t scaled_fraction = fraction;
00147   for (int i = 0; i < scale_shifts_size; ++i) {
00148     scaled_fraction += (fraction >> scale_shifts[i]);
00149   }
00150   *current = '1';
00151   current += 1;
00152   *current = '.';
00153   current += 1;
00154   *current = 0;
00155   current = StrCatUInt32(current, (current_end - current), scaled_fraction, 10);
00156   current = StrCatStr(current, (current_end - current), "*2^");
00157   current = StrCatInt32(current, (current_end - current), exponent);
00158   return current;
00159 }
00160 
00161 }  // namespace
00162 
00163 extern "C" void DebugLogInt32(int32_t i) {
00164   char number_string[kFastToBufferSize];
00165   FastInt32ToBufferLeft(i, number_string);
00166   DebugLog(number_string);
00167 }
00168 
00169 extern "C" void DebugLogUInt32(uint32_t i) {
00170   char number_string[kFastToBufferSize];
00171   FastUInt32ToBufferLeft(i, number_string, 10);
00172   DebugLog(number_string);
00173 }
00174 
00175 extern "C" void DebugLogHex(uint32_t i) {
00176   char number_string[kFastToBufferSize];
00177   FastUInt32ToBufferLeft(i, number_string, 16);
00178   DebugLog(number_string);
00179 }
00180 
00181 extern "C" void DebugLogFloat(float i) {
00182   char number_string[kFastToBufferSize];
00183   FastFloatToBufferLeft(i, number_string);
00184   DebugLog(number_string);
00185 }