aboutsummaryrefslogtreecommitdiffstats
path: root/util/string/benchmark/float_to_string/main.cpp
blob: c15b6009ad94a2731c26526f02d4dba1df374d32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#include <library/cpp/testing/benchmark/bench.h>
 
#include <util/generic/singleton.h> 
#include <util/generic/vector.h> 
#include <util/generic/xrange.h> 
#include <util/generic/ymath.h> 
#include <util/random/fast.h> 
#include <util/string/cast.h> 
#include <util/string/printf.h> 
 
#include <limits> 
 
#include <cmath> 
 
/* Please be careful before making any decisions based on this benchmark. 
 * 
 * Only `Sprintf("%.<decimals>f", x)` and `FloatToString(x, PREC_POINT_DIGITS, decimals` produce 
 * equal results in general case. However, results for cases when x \in [0, 1) must be equal for 
 * both `Sprintf` and `FloatToString`. 
 * 
 * Read more about formatting in STL [1, 2] and Yandex Util formatting [3] 
 * 
 * [1] http://www.cplusplus.com/reference/cstdio/printf/ 
 * [2] http://en.cppreference.com/w/c/io/fprintf 
 * [3] https://a.yandex-team.ru/arc/trunk/arcadia/util/string/cast.h?rev=2432660#L29 
 */ 
 
namespace { 
    template <typename T> 
    struct TExample { 
        T Value{}; 
        int DigitsCount{}; 
    }; 
 
    template <typename T, size_t N> 
    struct TExamplesHolder { 
        TVector<TExample<T>> Examples;
 
        TExamplesHolder() 
            : Examples(N)
        {
            TFastRng<ui64> prng{N * sizeof(T) * 42}; 
            for (auto& x : Examples) { 
                x.Value = prng.GenRandReal4() + prng.Uniform(Max<ui16>()); 
                x.DigitsCount = prng.Uniform(std::numeric_limits<T>::max_digits10 + 1); 
            } 
        } 
    }; 
 
    template <typename T, size_t N> 
    struct TNearZeroExamplesHolder { 
        TVector<TExample<T>> Examples;
 
        TNearZeroExamplesHolder() 
            : Examples(N)
        {
            TFastRng<ui64> prng{N * sizeof(T) * 42}; 
            for (auto& x : Examples) { 
                x.Value = prng.GenRandReal4(); 
                x.DigitsCount = prng.Uniform(std::numeric_limits<T>::max_digits10 + 1); 
            } 
        } 
    }; 
} 
 
static const char* FORMAT_FIXED[] = { 
    "%.0f", 
    "%.1f", 
    "%.2f", 
    "%.3f", 
    "%.4f", 
    "%.5f", 
    "%.6f", 
    "%.7f", 
    "%.8f", 
    "%.9f", 
    "%.10f", 
    "%.11f", 
    "%.12f", 
    "%.13f", 
    "%.14f", 
    "%.15f", 
    "%.16f", 
    "%.17f", 
}; 
 
static const char* FORMAT_SIGNIFICANT[] = { 
    "%.0g", 
    "%.1g", 
    "%.2g", 
    "%.3g", 
    "%.4g", 
    "%.5g", 
    "%.6g", 
    "%.7g", 
    "%.8g", 
    "%.9g", 
    "%.10g", 
    "%.11g", 
    "%.12g", 
    "%.13g", 
    "%.14g", 
    "%.15g", 
    "%.16g", 
    "%.17g", 
}; 
 
#define DEFINE_BENCHMARK(type, count)                                                                \ 
    Y_CPU_BENCHMARK(SprintfAuto_##type##_##count, iface) {                                           \ 
        const auto& examples = Default<TExamplesHolder<type, count>>().Examples;                     \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                /* this is in fact equal to Sprintf("%.6f", e.Value) and that is why it is faster */ \ 
                /* than FloatToString(e.Value) */                                                    \ 
                Y_DO_NOT_OPTIMIZE_AWAY(Sprintf("%f", e.Value));                                      \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(FloatToStringAuto_##type##_##count, iface) {                                     \ 
        const auto& examples = Default<TExamplesHolder<type, count>>().Examples;                     \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(FloatToString(e.Value));                                      \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(SprintfFixed_##type##_##count, iface) {                                          \ 
        const auto& examples = Default<TExamplesHolder<type, count>>().Examples;                     \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(Sprintf(FORMAT_FIXED[e.DigitsCount], e.Value));               \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(FloatToStringFixed_##type##_##count, iface) {                                    \ 
        const auto& examples = Default<TExamplesHolder<type, count>>().Examples;                     \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(FloatToString(e.Value, PREC_NDIGITS, e.DigitsCount));         \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(SprintfSignificant_##type##_##count, iface) {                                    \ 
        const auto& examples = Default<TExamplesHolder<type, count>>().Examples;                     \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(Sprintf(FORMAT_SIGNIFICANT[e.DigitsCount], e.Value));         \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(FloatToStringSignificant_##type##_##count, iface) {                              \ 
        const auto& examples = Default<TExamplesHolder<type, count>>().Examples;                     \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(FloatToString(e.Value, PREC_POINT_DIGITS, e.DigitsCount));    \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(NearZeroSprintfAuto_##type##_##count, iface) {                                   \ 
        const auto& examples = Default<TNearZeroExamplesHolder<type, count>>().Examples;             \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                /* this is in fact equal to Sprintf("%.6f", e.Value) and that is why it is faster */ \ 
                /* than FloatToString(e.Value) */                                                    \ 
                Y_DO_NOT_OPTIMIZE_AWAY(Sprintf("%f", e.Value));                                      \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(NearZeroFloatToStringAuto_##type##_##count, iface) {                             \ 
        const auto& examples = Default<TNearZeroExamplesHolder<type, count>>().Examples;             \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(FloatToString(e.Value));                                      \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(NearZeroSprintfFixed_##type##_##count, iface) {                                  \ 
        const auto& examples = Default<TNearZeroExamplesHolder<type, count>>().Examples;             \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(Sprintf(FORMAT_FIXED[e.DigitsCount], e.Value));               \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(NearZeroFloatToStringFixed_##type##_##count, iface) {                            \ 
        const auto& examples = Default<TNearZeroExamplesHolder<type, count>>().Examples;             \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(FloatToString(e.Value, PREC_NDIGITS, e.DigitsCount));         \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(NearZeroSprintfSignificant_##type##_##count, iface) {                            \ 
        const auto& examples = Default<TNearZeroExamplesHolder<type, count>>().Examples;             \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(Sprintf(FORMAT_SIGNIFICANT[e.DigitsCount], e.Value));         \ 
            }                                                                                        \ 
        }                                                                                            \ 
    }                                                                                                \ 
                                                                                                     \ 
    Y_CPU_BENCHMARK(NearZeroFloatToStringSignificant_##type##_##count, iface) {                      \ 
        const auto& examples = Default<TNearZeroExamplesHolder<type, count>>().Examples;             \ 
        for (const auto i : xrange(iface.Iterations())) {                                            \ 
            Y_UNUSED(i);                                                                             \ 
            for (const auto e : examples) {                                                          \ 
                Y_DO_NOT_OPTIMIZE_AWAY(FloatToString(e.Value, PREC_POINT_DIGITS, e.DigitsCount));    \ 
            }                                                                                        \ 
        }                                                                                            \ 
    } 
 
DEFINE_BENCHMARK(float, 1); 
DEFINE_BENCHMARK(float, 2); 
DEFINE_BENCHMARK(float, 4); 
DEFINE_BENCHMARK(float, 8); 
DEFINE_BENCHMARK(float, 16); 
DEFINE_BENCHMARK(float, 32); 
DEFINE_BENCHMARK(float, 64); 
DEFINE_BENCHMARK(float, 128); 
DEFINE_BENCHMARK(float, 256); 
 
DEFINE_BENCHMARK(double, 1); 
DEFINE_BENCHMARK(double, 2); 
DEFINE_BENCHMARK(double, 4); 
DEFINE_BENCHMARK(double, 8); 
DEFINE_BENCHMARK(double, 16); 
DEFINE_BENCHMARK(double, 32); 
DEFINE_BENCHMARK(double, 64); 
DEFINE_BENCHMARK(double, 128); 
DEFINE_BENCHMARK(double, 256); 
 
#undef DEFINE_BENCHMARK