Fix some rounding bugs
diff --git a/src/core/lib/debug/stats.c b/src/core/lib/debug/stats.c
index a65dfe4..91ca0aa 100644
--- a/src/core/lib/debug/stats.c
+++ b/src/core/lib/debug/stats.c
@@ -62,24 +62,21 @@
   }
 }
 
-int grpc_stats_histo_find_bucket_slow(grpc_exec_ctx *exec_ctx, double value,
+int grpc_stats_histo_find_bucket_slow(grpc_exec_ctx *exec_ctx, int value,
                                       const int *table, int table_size) {
   GRPC_STATS_INC_HISTOGRAM_SLOW_LOOKUPS(exec_ctx);
-  if (value < 0.0) return 0;
-  if (value >= table[table_size - 1]) return table_size - 1;
-  int a = 0;
-  int b = table_size - 1;
-  while (a < b) {
-    int c = a + ((b - a) / 2);
-    if (value < table[c]) {
-      b = c - 1;
-    } else if (value > table[c]) {
-      a = c + 1;
+  const int *const start = table;
+  while (table_size > 0) {
+    int step = table_size / 2;
+    const int *it = table + step;
+    if (value >= *it) {
+      table = it + 1;
+      table_size -= step + 1;
     } else {
-      return c;
+      table_size = step;
     }
   }
-  return a;
+  return (int)(table - start) - 1;
 }
 
 size_t grpc_stats_histo_count(const grpc_stats_data *stats,
diff --git a/src/core/lib/debug/stats.h b/src/core/lib/debug/stats.h
index 9d729c2..09d190d 100644
--- a/src/core/lib/debug/stats.h
+++ b/src/core/lib/debug/stats.h
@@ -50,7 +50,7 @@
 void grpc_stats_diff(const grpc_stats_data *b, const grpc_stats_data *a,
                      grpc_stats_data *c);
 char *grpc_stats_data_as_json(const grpc_stats_data *data);
-int grpc_stats_histo_find_bucket_slow(grpc_exec_ctx *exec_ctx, double value,
+int grpc_stats_histo_find_bucket_slow(grpc_exec_ctx *exec_ctx, int value,
                                       const int *table, int table_size);
 double grpc_stats_histo_percentile(const grpc_stats_data *data,
                                    grpc_stats_histograms histogram,
diff --git a/src/core/lib/debug/stats_data.c b/src/core/lib/debug/stats_data.c
index 4829f78..57cbafc 100644
--- a/src/core/lib/debug/stats_data.c
+++ b/src/core/lib/debug/stats_data.c
@@ -91,17 +91,20 @@
   union {
     double dbl;
     uint64_t uint;
-  } _val;
+  } _val, _bkt;
   _val.dbl = value;
   if (_val.uint < 4682617712558473216ull) {
-    GRPC_STATS_INC_HISTOGRAM(
-        (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE,
-        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 4);
+    int bucket =
+        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 5;
+    _bkt.dbl = grpc_stats_table_0[bucket];
+    bucket -= (_val.uint < _bkt.uint);
+    GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE,
+                             bucket);
     return;
   }
   GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE,
                            grpc_stats_histo_find_bucket_slow(
-                               (exec_ctx), _val.dbl, grpc_stats_table_0, 64));
+                               (exec_ctx), value, grpc_stats_table_0, 64));
 }
 void grpc_stats_inc_tcp_write_iov_size(grpc_exec_ctx *exec_ctx, int value) {
   value = GPR_CLAMP(value, 0, 1024);
@@ -113,17 +116,20 @@
   union {
     double dbl;
     uint64_t uint;
-  } _val;
+  } _val, _bkt;
   _val.dbl = value;
   if (_val.uint < 4637300241308057600ull) {
-    GRPC_STATS_INC_HISTOGRAM(
-        (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE,
-        grpc_stats_table_3[((_val.uint - 4622945017495814144ull) >> 48)] + 11);
+    int bucket =
+        grpc_stats_table_3[((_val.uint - 4622945017495814144ull) >> 48)] + 12;
+    _bkt.dbl = grpc_stats_table_2[bucket];
+    bucket -= (_val.uint < _bkt.uint);
+    GRPC_STATS_INC_HISTOGRAM((exec_ctx),
+                             GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE, bucket);
     return;
   }
   GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE,
                            grpc_stats_histo_find_bucket_slow(
-                               (exec_ctx), _val.dbl, grpc_stats_table_2, 64));
+                               (exec_ctx), value, grpc_stats_table_2, 64));
 }
 void grpc_stats_inc_tcp_read_size(grpc_exec_ctx *exec_ctx, int value) {
   value = GPR_CLAMP(value, 0, 16777216);
@@ -135,17 +141,20 @@
   union {
     double dbl;
     uint64_t uint;
-  } _val;
+  } _val, _bkt;
   _val.dbl = value;
   if (_val.uint < 4682617712558473216ull) {
-    GRPC_STATS_INC_HISTOGRAM(
-        (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_SIZE,
-        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 4);
+    int bucket =
+        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 5;
+    _bkt.dbl = grpc_stats_table_0[bucket];
+    bucket -= (_val.uint < _bkt.uint);
+    GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_SIZE,
+                             bucket);
     return;
   }
   GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_SIZE,
                            grpc_stats_histo_find_bucket_slow(
-                               (exec_ctx), _val.dbl, grpc_stats_table_0, 64));
+                               (exec_ctx), value, grpc_stats_table_0, 64));
 }
 void grpc_stats_inc_tcp_read_offer(grpc_exec_ctx *exec_ctx, int value) {
   value = GPR_CLAMP(value, 0, 16777216);
@@ -157,17 +166,20 @@
   union {
     double dbl;
     uint64_t uint;
-  } _val;
+  } _val, _bkt;
   _val.dbl = value;
   if (_val.uint < 4682617712558473216ull) {
-    GRPC_STATS_INC_HISTOGRAM(
-        (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_OFFER,
-        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 4);
+    int bucket =
+        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 5;
+    _bkt.dbl = grpc_stats_table_0[bucket];
+    bucket -= (_val.uint < _bkt.uint);
+    GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_OFFER,
+                             bucket);
     return;
   }
   GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_OFFER,
                            grpc_stats_histo_find_bucket_slow(
-                               (exec_ctx), _val.dbl, grpc_stats_table_0, 64));
+                               (exec_ctx), value, grpc_stats_table_0, 64));
 }
 void grpc_stats_inc_tcp_read_iov_size(grpc_exec_ctx *exec_ctx, int value) {
   value = GPR_CLAMP(value, 0, 1024);
@@ -179,17 +191,20 @@
   union {
     double dbl;
     uint64_t uint;
-  } _val;
+  } _val, _bkt;
   _val.dbl = value;
   if (_val.uint < 4637300241308057600ull) {
-    GRPC_STATS_INC_HISTOGRAM(
-        (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE,
-        grpc_stats_table_3[((_val.uint - 4622945017495814144ull) >> 48)] + 11);
+    int bucket =
+        grpc_stats_table_3[((_val.uint - 4622945017495814144ull) >> 48)] + 12;
+    _bkt.dbl = grpc_stats_table_2[bucket];
+    bucket -= (_val.uint < _bkt.uint);
+    GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE,
+                             bucket);
     return;
   }
   GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE,
                            grpc_stats_histo_find_bucket_slow(
-                               (exec_ctx), _val.dbl, grpc_stats_table_2, 64));
+                               (exec_ctx), value, grpc_stats_table_2, 64));
 }
 void grpc_stats_inc_http2_send_message_size(grpc_exec_ctx *exec_ctx,
                                             int value) {
@@ -202,18 +217,21 @@
   union {
     double dbl;
     uint64_t uint;
-  } _val;
+  } _val, _bkt;
   _val.dbl = value;
   if (_val.uint < 4682617712558473216ull) {
+    int bucket =
+        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 5;
+    _bkt.dbl = grpc_stats_table_0[bucket];
+    bucket -= (_val.uint < _bkt.uint);
     GRPC_STATS_INC_HISTOGRAM(
-        (exec_ctx), GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE,
-        grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)] + 4);
+        (exec_ctx), GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE, bucket);
     return;
   }
   GRPC_STATS_INC_HISTOGRAM((exec_ctx),
                            GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE,
                            grpc_stats_histo_find_bucket_slow(
-                               (exec_ctx), _val.dbl, grpc_stats_table_0, 64));
+                               (exec_ctx), value, grpc_stats_table_0, 64));
 }
 const int grpc_stats_histo_buckets[6] = {64, 64, 64, 64, 64, 64};
 const int grpc_stats_histo_start[6] = {0, 64, 128, 192, 256, 320};
diff --git a/tools/codegen/core/gen_stats_data.py b/tools/codegen/core/gen_stats_data.py
index a15745c..104ac83 100755
--- a/tools/codegen/core/gen_stats_data.py
+++ b/tools/codegen/core/gen_stats_data.py
@@ -144,15 +144,18 @@
     first_nontrivial_code = dbl2u64(first_nontrivial)
     if shift_data is not None:
       map_table_idx = decl_static_table(map_table, type_for_uint_table(map_table))
-      code += 'union { double dbl; uint64_t uint; } _val;\n'
+      code += 'union { double dbl; uint64_t uint; } _val, _bkt;\n'
       code += '_val.dbl = value;\n'
       code += 'if (_val.uint < %dull) {\n' % ((map_table[-1] << shift_data[0]) + first_nontrivial_code)
-      code += 'GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_%s, ' % histogram.name.upper()
-      code += 'grpc_stats_table_%d[((_val.uint - %dull) >> %d)] + %d);\n' % (map_table_idx, first_nontrivial_code, shift_data[0], first_nontrivial-1)
+      code += 'int bucket = '
+      code += 'grpc_stats_table_%d[((_val.uint - %dull) >> %d)] + %d;\n' % (map_table_idx, first_nontrivial_code, shift_data[0], first_nontrivial)
+      code += '_bkt.dbl = grpc_stats_table_%d[bucket];\n' % bounds_idx
+      code += 'bucket -= (_val.uint < _bkt.uint);\n'
+      code += 'GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_%s, bucket);\n' % histogram.name.upper()
       code += 'return;\n'
       code += '}\n'
     code += 'GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_%s, '% histogram.name.upper()
-    code += 'grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, grpc_stats_table_%d, %d));\n' % (bounds_idx, len(bounds))
+    code += 'grpc_stats_histo_find_bucket_slow((exec_ctx), value, grpc_stats_table_%d, %d));\n' % (bounds_idx, len(bounds))
   return (code, bounds_idx)
 
 # utility: print a big comment block into a set of files