fast_excel 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -7
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -1
- data/examples/example.rb +2 -0
- data/examples/example_date_time.rb +38 -0
- data/fast_excel.gemspec +2 -2
- data/lib/fast_excel/binding/format.rb +17 -0
- data/lib/fast_excel/binding/workbook.rb +39 -17
- data/lib/fast_excel/binding/worksheet.rb +57 -13
- data/lib/fast_excel/binding.rb +7 -7
- data/lib/fast_excel.rb +27 -20
- data/libxlsxwriter/.github/FUNDING.yml +1 -0
- data/libxlsxwriter/.github/ISSUE_TEMPLATE.md +85 -0
- data/libxlsxwriter/.github/PULL_REQUEST_TEMPLATE.md +130 -0
- data/libxlsxwriter/.github/workflows/cmake_actions.yml +48 -0
- data/libxlsxwriter/.github/workflows/code_style.yml +23 -0
- data/libxlsxwriter/.github/workflows/coverity.yml +22 -0
- data/libxlsxwriter/.github/workflows/make_actions.yml +52 -0
- data/libxlsxwriter/.github/workflows/valgrind.yml +23 -0
- data/libxlsxwriter/.github/workflows/windows_build.yml +54 -0
- data/libxlsxwriter/.github/workflows/zig_build.yml +22 -0
- data/libxlsxwriter/.gitignore +16 -1
- data/libxlsxwriter/.indent.pro +24 -0
- data/libxlsxwriter/CMakeLists.txt +156 -56
- data/libxlsxwriter/CONTRIBUTING.md +2 -2
- data/libxlsxwriter/Changes.txt +344 -2
- data/libxlsxwriter/LICENSE.txt +66 -8
- data/libxlsxwriter/Makefile +151 -54
- data/libxlsxwriter/Package.swift +42 -0
- data/libxlsxwriter/Readme.md +4 -2
- data/libxlsxwriter/build.zig +324 -0
- data/libxlsxwriter/build.zig.zon +11 -0
- data/libxlsxwriter/cmake/FindMINIZIP.cmake +3 -3
- data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +6 -0
- data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/chart.h +236 -32
- data/libxlsxwriter/include/xlsxwriter/chartsheet.h +7 -7
- data/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
- data/libxlsxwriter/include/xlsxwriter/common.h +111 -50
- data/libxlsxwriter/include/xlsxwriter/content_types.h +8 -1
- data/libxlsxwriter/include/xlsxwriter/core.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/drawing.h +11 -20
- data/libxlsxwriter/include/xlsxwriter/format.h +121 -8
- data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/metadata.h +49 -0
- data/libxlsxwriter/include/xlsxwriter/packager.h +27 -16
- data/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/styles.h +13 -7
- data/libxlsxwriter/include/xlsxwriter/table.h +51 -0
- data/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/third_party/emyg_dtoa.h +26 -0
- data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +27 -25
- data/libxlsxwriter/include/xlsxwriter/third_party/md5.h +45 -0
- data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +155 -153
- data/libxlsxwriter/include/xlsxwriter/utility.h +70 -8
- data/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
- data/libxlsxwriter/include/xlsxwriter/workbook.h +218 -47
- data/libxlsxwriter/include/xlsxwriter/worksheet.h +2770 -241
- data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +12 -8
- data/libxlsxwriter/include/xlsxwriter.h +4 -2
- data/libxlsxwriter/libxlsxwriter.podspec +8 -5
- data/libxlsxwriter/src/Makefile +58 -21
- data/libxlsxwriter/src/app.c +5 -2
- data/libxlsxwriter/src/chart.c +396 -81
- data/libxlsxwriter/src/chartsheet.c +22 -22
- data/libxlsxwriter/src/comment.c +443 -0
- data/libxlsxwriter/src/content_types.c +40 -1
- data/libxlsxwriter/src/core.c +2 -2
- data/libxlsxwriter/src/custom.c +1 -1
- data/libxlsxwriter/src/drawing.c +160 -40
- data/libxlsxwriter/src/format.c +109 -25
- data/libxlsxwriter/src/hash_table.c +1 -1
- data/libxlsxwriter/src/metadata.c +283 -0
- data/libxlsxwriter/src/packager.c +794 -94
- data/libxlsxwriter/src/relationships.c +1 -1
- data/libxlsxwriter/src/shared_strings.c +2 -4
- data/libxlsxwriter/src/styles.c +353 -58
- data/libxlsxwriter/src/table.c +304 -0
- data/libxlsxwriter/src/theme.c +1 -1
- data/libxlsxwriter/src/utility.c +143 -43
- data/libxlsxwriter/src/vml.c +1062 -0
- data/libxlsxwriter/src/workbook.c +567 -77
- data/libxlsxwriter/src/worksheet.c +6668 -1462
- data/libxlsxwriter/src/xmlwriter.c +95 -5
- data/libxlsxwriter/third_party/dtoa/Makefile +42 -0
- data/libxlsxwriter/third_party/dtoa/emyg_dtoa.c +461 -0
- data/libxlsxwriter/third_party/dtoa/emyg_dtoa.h +26 -0
- data/libxlsxwriter/third_party/md5/Makefile +42 -0
- data/libxlsxwriter/third_party/md5/md5.c +291 -0
- data/libxlsxwriter/third_party/md5/md5.h +45 -0
- data/libxlsxwriter/third_party/minizip/Makefile +3 -8
- data/libxlsxwriter/third_party/minizip/Makefile.orig +8 -4
- data/libxlsxwriter/third_party/minizip/MiniZip64_Changes.txt +1 -1
- data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
- data/libxlsxwriter/third_party/minizip/crypt.h +13 -16
- data/libxlsxwriter/third_party/minizip/ioapi.c +31 -57
- data/libxlsxwriter/third_party/minizip/ioapi.h +31 -23
- data/libxlsxwriter/third_party/minizip/iowin32.c +29 -45
- data/libxlsxwriter/third_party/minizip/iowin32.h +4 -4
- data/libxlsxwriter/third_party/minizip/miniunz.c +29 -56
- data/libxlsxwriter/third_party/minizip/minizip.c +38 -49
- data/libxlsxwriter/third_party/minizip/mztools.c +1 -7
- data/libxlsxwriter/third_party/minizip/unzip.c +202 -342
- data/libxlsxwriter/third_party/minizip/unzip.h +74 -74
- data/libxlsxwriter/third_party/minizip/zip.c +165 -218
- data/libxlsxwriter/third_party/minizip/zip.h +164 -154
- data/libxlsxwriter/third_party/tmpfileplus/Makefile +3 -3
- data/libxlsxwriter/version.txt +1 -1
- data/test/auto_width_test.rb +20 -0
- data/test/default_format_test.rb +1 -1
- data/test/validations_test.rb +3 -3
- data/test/worksheet_test.rb +6 -1
- metadata +33 -7
- data/libxlsxwriter/.travis.yml +0 -37
|
@@ -3,19 +3,21 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
|
5
5
|
*
|
|
6
|
-
* Copyright 2014-
|
|
6
|
+
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
#include <stdio.h>
|
|
11
11
|
#include <string.h>
|
|
12
12
|
#include <stdlib.h>
|
|
13
|
+
#include <ctype.h>
|
|
13
14
|
#include "xlsxwriter/xmlwriter.h"
|
|
14
15
|
|
|
15
16
|
#define LXW_AMP "&"
|
|
16
17
|
#define LXW_LT "<"
|
|
17
18
|
#define LXW_GT ">"
|
|
18
19
|
#define LXW_QUOT """
|
|
20
|
+
#define LXW_NL "
"
|
|
19
21
|
|
|
20
22
|
/* Defines. */
|
|
21
23
|
#define LXW_MAX_ENCODED_ATTRIBUTE_LENGTH (LXW_MAX_ATTRIBUTE_LENGTH*6)
|
|
@@ -177,6 +179,10 @@ _escape_attributes(struct xml_attribute *attribute)
|
|
|
177
179
|
memcpy(p_encoded, LXW_QUOT, sizeof(LXW_QUOT) - 1);
|
|
178
180
|
p_encoded += sizeof(LXW_QUOT) - 1;
|
|
179
181
|
break;
|
|
182
|
+
case '\n':
|
|
183
|
+
memcpy(p_encoded, LXW_NL, sizeof(LXW_NL) - 1);
|
|
184
|
+
p_encoded += sizeof(LXW_NL) - 1;
|
|
185
|
+
break;
|
|
180
186
|
default:
|
|
181
187
|
*p_encoded = *p_attr;
|
|
182
188
|
p_encoded++;
|
|
@@ -227,7 +233,24 @@ lxw_escape_data(const char *data)
|
|
|
227
233
|
}
|
|
228
234
|
|
|
229
235
|
/*
|
|
230
|
-
*
|
|
236
|
+
* Check for control characters in strings.
|
|
237
|
+
*/
|
|
238
|
+
uint8_t
|
|
239
|
+
lxw_has_control_characters(const char *string)
|
|
240
|
+
{
|
|
241
|
+
while (string) {
|
|
242
|
+
/* 0xE0 == 0b11100000 masks values > 0x19 == 0b00011111. */
|
|
243
|
+
if (!(*string & 0xE0) && *string != 0x0A && *string != 0x09)
|
|
244
|
+
return LXW_TRUE;
|
|
245
|
+
|
|
246
|
+
string++;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return LXW_FALSE;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/*
|
|
253
|
+
* Escape control characters in strings with _xHHHH_.
|
|
231
254
|
*/
|
|
232
255
|
char *
|
|
233
256
|
lxw_escape_control_characters(const char *string)
|
|
@@ -283,6 +306,67 @@ lxw_escape_control_characters(const char *string)
|
|
|
283
306
|
return encoded;
|
|
284
307
|
}
|
|
285
308
|
|
|
309
|
+
/*
|
|
310
|
+
* Escape special characters in URL strings with with %XX.
|
|
311
|
+
*/
|
|
312
|
+
char *
|
|
313
|
+
lxw_escape_url_characters(const char *string, uint8_t escape_hash)
|
|
314
|
+
{
|
|
315
|
+
|
|
316
|
+
size_t escape_len = sizeof("%XX") - 1;
|
|
317
|
+
size_t encoded_len = (strlen(string) * escape_len + 1);
|
|
318
|
+
|
|
319
|
+
char *encoded = (char *) calloc(encoded_len, 1);
|
|
320
|
+
char *p_encoded = encoded;
|
|
321
|
+
|
|
322
|
+
while (*string) {
|
|
323
|
+
switch (*string) {
|
|
324
|
+
case ' ':
|
|
325
|
+
case '"':
|
|
326
|
+
case '<':
|
|
327
|
+
case '>':
|
|
328
|
+
case '[':
|
|
329
|
+
case ']':
|
|
330
|
+
case '`':
|
|
331
|
+
case '^':
|
|
332
|
+
case '{':
|
|
333
|
+
case '}':
|
|
334
|
+
lxw_snprintf(p_encoded, escape_len + 1, "%%%2x", *string);
|
|
335
|
+
p_encoded += escape_len;
|
|
336
|
+
break;
|
|
337
|
+
case '#':
|
|
338
|
+
/* This is only escaped for "external:" style links. */
|
|
339
|
+
if (escape_hash) {
|
|
340
|
+
lxw_snprintf(p_encoded, escape_len + 1, "%%%2x", *string);
|
|
341
|
+
p_encoded += escape_len;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
*p_encoded = *string;
|
|
345
|
+
p_encoded++;
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
case '%':
|
|
349
|
+
/* Only escape % if it isn't already an escape. */
|
|
350
|
+
if (!isxdigit(*(string + 1)) || !isxdigit(*(string + 2))) {
|
|
351
|
+
lxw_snprintf(p_encoded, escape_len + 1, "%%%2x", *string);
|
|
352
|
+
p_encoded += escape_len;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
*p_encoded = *string;
|
|
356
|
+
p_encoded++;
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
default:
|
|
360
|
+
*p_encoded = *string;
|
|
361
|
+
p_encoded++;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
string++;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return encoded;
|
|
368
|
+
}
|
|
369
|
+
|
|
286
370
|
/* Write out escaped attributes. */
|
|
287
371
|
STATIC void
|
|
288
372
|
_fprint_escaped_attributes(FILE * xmlfile,
|
|
@@ -294,7 +378,7 @@ _fprint_escaped_attributes(FILE * xmlfile,
|
|
|
294
378
|
STAILQ_FOREACH(attribute, attributes, list_entries) {
|
|
295
379
|
fprintf(xmlfile, " %s=", attribute->key);
|
|
296
380
|
|
|
297
|
-
if (!strpbrk(attribute->value, "&<>\"")) {
|
|
381
|
+
if (!strpbrk(attribute->value, "&<>\"\n")) {
|
|
298
382
|
fprintf(xmlfile, "\"%s\"", attribute->value);
|
|
299
383
|
}
|
|
300
384
|
else {
|
|
@@ -341,12 +425,18 @@ lxw_new_attribute_str(const char *key, const char *value)
|
|
|
341
425
|
|
|
342
426
|
/* Create a new integer XML attribute. */
|
|
343
427
|
struct xml_attribute *
|
|
344
|
-
lxw_new_attribute_int(const char *key,
|
|
428
|
+
lxw_new_attribute_int(const char *key, uint64_t value)
|
|
345
429
|
{
|
|
346
430
|
struct xml_attribute *attribute = malloc(sizeof(struct xml_attribute));
|
|
347
431
|
|
|
348
432
|
LXW_ATTRIBUTE_COPY(attribute->key, key);
|
|
349
|
-
|
|
433
|
+
|
|
434
|
+
#if defined(_MSC_VER)
|
|
435
|
+
lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%lld", value);
|
|
436
|
+
#else
|
|
437
|
+
lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%ld",
|
|
438
|
+
(long) value);
|
|
439
|
+
#endif
|
|
350
440
|
|
|
351
441
|
return attribute;
|
|
352
442
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# Simplied Makefile to build the emyg_dtoa library for libxlsxwriter.
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
# Keep the output quiet by default.
|
|
7
|
+
Q=@
|
|
8
|
+
ifdef V
|
|
9
|
+
Q=
|
|
10
|
+
endif
|
|
11
|
+
|
|
12
|
+
UNAME := $(shell uname)
|
|
13
|
+
|
|
14
|
+
# Check for MinGW/MinGW64/Cygwin environments.
|
|
15
|
+
ifneq (,$(findstring MINGW, $(UNAME)))
|
|
16
|
+
MING_LIKE = y
|
|
17
|
+
endif
|
|
18
|
+
ifneq (,$(findstring MSYS, $(UNAME)))
|
|
19
|
+
MING_LIKE = y
|
|
20
|
+
endif
|
|
21
|
+
ifneq (,$(findstring CYGWIN, $(UNAME)))
|
|
22
|
+
MING_LIKE = y
|
|
23
|
+
endif
|
|
24
|
+
|
|
25
|
+
FPIC = -fPIC
|
|
26
|
+
|
|
27
|
+
# Change make options on MinGW/MinGW64/Cygwin.
|
|
28
|
+
ifdef MING_LIKE
|
|
29
|
+
FPIC =
|
|
30
|
+
CC = gcc
|
|
31
|
+
endif
|
|
32
|
+
|
|
33
|
+
all: emyg_dtoa.o emyg_dtoa.so
|
|
34
|
+
|
|
35
|
+
%.o : %.c
|
|
36
|
+
$(Q)$(CC) -c $(CFLAGS) $<
|
|
37
|
+
|
|
38
|
+
%.so : %.c
|
|
39
|
+
$(Q)$(CC) $(FPIC) -c $(CFLAGS) $< -o $@
|
|
40
|
+
|
|
41
|
+
clean:
|
|
42
|
+
$(Q)rm -f *.o *.so
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/* emyg_dtoa.c
|
|
2
|
+
** Copyright (C) 2015 Doug Currie
|
|
3
|
+
** based on dtoa_milo.h
|
|
4
|
+
** Copyright (C) 2014 Milo Yip
|
|
5
|
+
**
|
|
6
|
+
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
** of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
** in the Software without restriction, including without limitation the rights
|
|
9
|
+
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
** copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
** furnished to do so, subject to the following conditions:
|
|
12
|
+
**
|
|
13
|
+
** The above copyright notice and this permission notice shall be included in
|
|
14
|
+
** all copies or substantial portions of the Software.
|
|
15
|
+
**
|
|
16
|
+
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
** THE SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/* This code is a mostly mechanical translation of Milo Yip's C++ version of
|
|
26
|
+
** Grisu2 to C. For algorithm information, see Loitsch, Florian. "Printing
|
|
27
|
+
** floating-point numbers quickly and accurately with integers." ACM Sigplan
|
|
28
|
+
** Notices 45.6 (2010): 233-243.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/* Source from https://github.com/miloyip/dtoa-benchmark */
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
#include <assert.h>
|
|
35
|
+
#include <math.h>
|
|
36
|
+
|
|
37
|
+
#if defined(_MSC_VER)
|
|
38
|
+
#include <stdint.h>
|
|
39
|
+
#include <intrin.h>
|
|
40
|
+
#include <float.h>
|
|
41
|
+
#else
|
|
42
|
+
#include <stdint.h>
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
#include <string.h>
|
|
46
|
+
|
|
47
|
+
#include "emyg_dtoa.h"
|
|
48
|
+
|
|
49
|
+
#define UINT64_C2(h, l) (((uint64_t )(h) << 32) | (uint64_t )(l))
|
|
50
|
+
|
|
51
|
+
typedef struct DiyFp_s {
|
|
52
|
+
uint64_t f;
|
|
53
|
+
int e;
|
|
54
|
+
} DiyFp;
|
|
55
|
+
|
|
56
|
+
static const int kDiySignificandSize = 64;
|
|
57
|
+
static const int kDpSignificandSize = 52;
|
|
58
|
+
static const int kDpExponentBias = 0x3FF + 52;
|
|
59
|
+
static const int kDpMinExponent = -0x3FF - 52;
|
|
60
|
+
static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000);
|
|
61
|
+
static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
|
62
|
+
static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000);
|
|
63
|
+
|
|
64
|
+
static __inline DiyFp DiyFp_from_parts (uint64_t f, int e) {
|
|
65
|
+
DiyFp fp;
|
|
66
|
+
fp.f = f;
|
|
67
|
+
fp.e = e;
|
|
68
|
+
return fp;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
DiyFp DiyFp_from_double (double d) {
|
|
72
|
+
DiyFp res;
|
|
73
|
+
int biased_e;
|
|
74
|
+
uint64_t significand;
|
|
75
|
+
union {
|
|
76
|
+
double d;
|
|
77
|
+
uint64_t u64;
|
|
78
|
+
} u;
|
|
79
|
+
|
|
80
|
+
u.d = d;
|
|
81
|
+
biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
|
|
82
|
+
significand = (u.u64 & kDpSignificandMask);
|
|
83
|
+
|
|
84
|
+
if (biased_e != 0) {
|
|
85
|
+
res.f = significand + kDpHiddenBit;
|
|
86
|
+
res.e = biased_e - kDpExponentBias;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
res.f = significand;
|
|
90
|
+
res.e = kDpMinExponent + 1;
|
|
91
|
+
}
|
|
92
|
+
return res;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static __inline DiyFp DiyFp_subtract (const DiyFp lhs, const DiyFp rhs) {
|
|
96
|
+
assert(lhs.e == rhs.e);
|
|
97
|
+
assert(lhs.f >= rhs.f);
|
|
98
|
+
return DiyFp_from_parts(lhs.f - rhs.f, lhs.e);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
static __inline DiyFp DiyFp_multiply (const DiyFp lhs, const DiyFp rhs) {
|
|
102
|
+
#if defined(_MSC_VER) && defined(_M_AMD64)
|
|
103
|
+
uint64_t h;
|
|
104
|
+
uint64_t l = _umul128(lhs.f, rhs.f, &h);
|
|
105
|
+
/* Handle rounding. */
|
|
106
|
+
if (l & ((uint64_t)1u << 63))
|
|
107
|
+
h++;
|
|
108
|
+
return DiyFp_from_parts(h, lhs.e + rhs.e + 64);
|
|
109
|
+
#elif ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __clang_major__ >= 9) && defined(__x86_64__))
|
|
110
|
+
unsigned __int128 p = (unsigned __int128 )(lhs.f) * (unsigned __int128 )(rhs.f);
|
|
111
|
+
uint64_t h = p >> 64;
|
|
112
|
+
uint64_t l = (uint64_t )(p);
|
|
113
|
+
/* Handle rounding. */
|
|
114
|
+
if (l & ((uint64_t)1u << 63))
|
|
115
|
+
h++;
|
|
116
|
+
return DiyFp_from_parts(h, lhs.e + rhs.e + 64);
|
|
117
|
+
#else
|
|
118
|
+
const uint64_t M32 = 0xFFFFFFFF;
|
|
119
|
+
const uint64_t a = lhs.f >> 32;
|
|
120
|
+
const uint64_t b = lhs.f & M32;
|
|
121
|
+
const uint64_t c = rhs.f >> 32;
|
|
122
|
+
const uint64_t d = rhs.f & M32;
|
|
123
|
+
const uint64_t ac = a * c;
|
|
124
|
+
const uint64_t bc = b * c;
|
|
125
|
+
const uint64_t ad = a * d;
|
|
126
|
+
const uint64_t bd = b * d;
|
|
127
|
+
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
|
128
|
+
tmp += 1U << 31; /* mult_round */
|
|
129
|
+
return DiyFp_from_parts(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), lhs.e + rhs.e + 64);
|
|
130
|
+
#endif
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static __inline DiyFp Normalize (const DiyFp lhs) {
|
|
134
|
+
#if defined(_MSC_VER) && defined(_M_AMD64)
|
|
135
|
+
unsigned long index;
|
|
136
|
+
_BitScanReverse64(&index, lhs.f);
|
|
137
|
+
return DiyFp_from_parts(lhs.f << (63 - index), lhs.e - (63 - index));
|
|
138
|
+
#elif defined(__GNUC__)
|
|
139
|
+
int s = __builtin_clzll(lhs.f);
|
|
140
|
+
return DiyFp_from_parts(lhs.f << s, lhs.e - s);
|
|
141
|
+
#else
|
|
142
|
+
DiyFp res = lhs;
|
|
143
|
+
while (!(res.f & kDpHiddenBit)) {
|
|
144
|
+
res.f <<= 1;
|
|
145
|
+
res.e--;
|
|
146
|
+
}
|
|
147
|
+
res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
|
|
148
|
+
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
|
|
149
|
+
return res;
|
|
150
|
+
#endif
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static __inline DiyFp NormalizeBoundary (const DiyFp lhs) {
|
|
154
|
+
#if defined(_MSC_VER) && defined(_M_AMD64)
|
|
155
|
+
unsigned long index;
|
|
156
|
+
_BitScanReverse64(&index, lhs.f);
|
|
157
|
+
return DiyFp_from_parts(lhs.f << (63 - index), lhs.e - (63 - index));
|
|
158
|
+
#else
|
|
159
|
+
DiyFp res = lhs;
|
|
160
|
+
while (!(res.f & (kDpHiddenBit << 1))) {
|
|
161
|
+
res.f <<= 1;
|
|
162
|
+
res.e--;
|
|
163
|
+
}
|
|
164
|
+
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
|
165
|
+
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
|
166
|
+
return res;
|
|
167
|
+
#endif
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
static __inline void NormalizedBoundaries (DiyFp lhs, DiyFp* minus, DiyFp* plus) {
|
|
171
|
+
DiyFp pl = NormalizeBoundary(DiyFp_from_parts((lhs.f << 1) + 1, lhs.e - 1));
|
|
172
|
+
DiyFp mi = (lhs.f == kDpHiddenBit)
|
|
173
|
+
? DiyFp_from_parts((lhs.f << 2) - 1, lhs.e - 2)
|
|
174
|
+
: DiyFp_from_parts((lhs.f << 1) - 1, lhs.e - 1);
|
|
175
|
+
mi.f <<= mi.e - pl.e;
|
|
176
|
+
mi.e = pl.e;
|
|
177
|
+
*plus = pl;
|
|
178
|
+
*minus = mi;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static __inline DiyFp GetCachedPower (int e, int* K) {
|
|
182
|
+
unsigned index;
|
|
183
|
+
|
|
184
|
+
/* 10^-348, 10^-340, ..., 10^340 */
|
|
185
|
+
static const uint64_t kCachedPowers_F[] = {
|
|
186
|
+
UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
|
187
|
+
UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea),
|
|
188
|
+
UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
|
|
189
|
+
UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
|
190
|
+
UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
|
191
|
+
UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
|
192
|
+
UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d),
|
|
193
|
+
UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637),
|
|
194
|
+
UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
|
|
195
|
+
UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5),
|
|
196
|
+
UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
|
197
|
+
UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
|
|
198
|
+
UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
|
199
|
+
UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
|
200
|
+
UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
|
|
201
|
+
UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd),
|
|
202
|
+
UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94),
|
|
203
|
+
UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
|
204
|
+
UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
|
205
|
+
UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3),
|
|
206
|
+
UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
|
|
207
|
+
UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c),
|
|
208
|
+
UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000),
|
|
209
|
+
UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
|
|
210
|
+
UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
|
211
|
+
UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245),
|
|
212
|
+
UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
|
213
|
+
UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a),
|
|
214
|
+
UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea),
|
|
215
|
+
UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
|
|
216
|
+
UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
|
217
|
+
UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
|
218
|
+
UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
|
|
219
|
+
UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
|
220
|
+
UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
|
221
|
+
UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
|
222
|
+
UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
|
223
|
+
UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
|
224
|
+
UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
|
|
225
|
+
UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429),
|
|
226
|
+
UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d),
|
|
227
|
+
UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
|
|
228
|
+
UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
|
229
|
+
UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
|
230
|
+
};
|
|
231
|
+
static const int16_t kCachedPowers_E[] = {
|
|
232
|
+
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
|
233
|
+
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
|
234
|
+
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
|
235
|
+
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
|
236
|
+
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
|
237
|
+
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
|
238
|
+
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
|
239
|
+
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
|
240
|
+
907, 933, 960, 986, 1013, 1039, 1066
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/* dk must be positive, so can do ceiling in positive */
|
|
244
|
+
double dk = (-61 - e) * 0.30102999566398114 + 347;
|
|
245
|
+
int k = (int )(dk);
|
|
246
|
+
if (k != dk)
|
|
247
|
+
k++;
|
|
248
|
+
|
|
249
|
+
index = (unsigned )((k >> 3) + 1);
|
|
250
|
+
/* decimal exponent no need lookup table */
|
|
251
|
+
*K = -(-348 + (int )(index << 3));
|
|
252
|
+
|
|
253
|
+
assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0]));
|
|
254
|
+
return DiyFp_from_parts(kCachedPowers_F[index], kCachedPowers_E[index]);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
static __inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
|
258
|
+
while (rest < wp_w && delta - rest >= ten_kappa &&
|
|
259
|
+
(rest + ten_kappa < wp_w || /* closer */
|
|
260
|
+
wp_w - rest > rest + ten_kappa - wp_w)) {
|
|
261
|
+
buffer[len - 1]--;
|
|
262
|
+
rest += ten_kappa;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static __inline unsigned CountDecimalDigit32(uint32_t n) {
|
|
267
|
+
/* Simple pure C++ implementation was faster than __builtin_clz version in this situation. */
|
|
268
|
+
if (n < 10) return 1;
|
|
269
|
+
if (n < 100) return 2;
|
|
270
|
+
if (n < 1000) return 3;
|
|
271
|
+
if (n < 10000) return 4;
|
|
272
|
+
if (n < 100000) return 5;
|
|
273
|
+
if (n < 1000000) return 6;
|
|
274
|
+
if (n < 10000000) return 7;
|
|
275
|
+
if (n < 100000000) return 8;
|
|
276
|
+
if (n < 1000000000) return 9;
|
|
277
|
+
return 10;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
static __inline void DigitGen(const DiyFp W, const DiyFp Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
|
281
|
+
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
|
282
|
+
const DiyFp one = DiyFp_from_parts((uint64_t )(1) << -Mp.e, Mp.e);
|
|
283
|
+
const DiyFp wp_w = DiyFp_subtract(Mp, W);
|
|
284
|
+
uint32_t p1 = (uint32_t )(Mp.f >> -one.e);
|
|
285
|
+
uint64_t p2 = Mp.f & (one.f - 1);
|
|
286
|
+
int kappa = (int )(CountDecimalDigit32(p1));
|
|
287
|
+
*len = 0;
|
|
288
|
+
|
|
289
|
+
while (kappa > 0) {
|
|
290
|
+
uint32_t d;
|
|
291
|
+
uint64_t tmp;
|
|
292
|
+
switch (kappa) {
|
|
293
|
+
case 10: d = p1 / 1000000000; p1 %= 1000000000; break;
|
|
294
|
+
case 9: d = p1 / 100000000; p1 %= 100000000; break;
|
|
295
|
+
case 8: d = p1 / 10000000; p1 %= 10000000; break;
|
|
296
|
+
case 7: d = p1 / 1000000; p1 %= 1000000; break;
|
|
297
|
+
case 6: d = p1 / 100000; p1 %= 100000; break;
|
|
298
|
+
case 5: d = p1 / 10000; p1 %= 10000; break;
|
|
299
|
+
case 4: d = p1 / 1000; p1 %= 1000; break;
|
|
300
|
+
case 3: d = p1 / 100; p1 %= 100; break;
|
|
301
|
+
case 2: d = p1 / 10; p1 %= 10; break;
|
|
302
|
+
case 1: d = p1; p1 = 0; break;
|
|
303
|
+
default:
|
|
304
|
+
#if defined(_MSC_VER)
|
|
305
|
+
__assume(0);
|
|
306
|
+
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
|
307
|
+
__builtin_unreachable();
|
|
308
|
+
#else
|
|
309
|
+
d = 0;
|
|
310
|
+
#endif
|
|
311
|
+
}
|
|
312
|
+
if (d || *len)
|
|
313
|
+
buffer[(*len)++] = '0' + (char )(d);
|
|
314
|
+
kappa--;
|
|
315
|
+
tmp = ((uint64_t )(p1) << -one.e) + p2;
|
|
316
|
+
if (tmp <= delta) {
|
|
317
|
+
*K += kappa;
|
|
318
|
+
GrisuRound(buffer, *len, delta, tmp, (uint64_t )(kPow10[kappa]) << -one.e, wp_w.f);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* kappa = 0 */
|
|
324
|
+
for (;;) {
|
|
325
|
+
char d;
|
|
326
|
+
p2 *= 10;
|
|
327
|
+
delta *= 10;
|
|
328
|
+
d = (char )(p2 >> -one.e);
|
|
329
|
+
if (d || *len)
|
|
330
|
+
buffer[(*len)++] = '0' + d;
|
|
331
|
+
p2 &= one.f - 1;
|
|
332
|
+
kappa--;
|
|
333
|
+
if (p2 < delta) {
|
|
334
|
+
*K += kappa;
|
|
335
|
+
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
static __inline void Grisu2(double value, char* buffer, int* length, int* K) {
|
|
342
|
+
const DiyFp v = DiyFp_from_double(value);
|
|
343
|
+
DiyFp c_mk;
|
|
344
|
+
DiyFp W;
|
|
345
|
+
DiyFp w_m, w_p;
|
|
346
|
+
DiyFp Wp;
|
|
347
|
+
DiyFp Wm;
|
|
348
|
+
NormalizedBoundaries(v, &w_m, &w_p);
|
|
349
|
+
|
|
350
|
+
c_mk = GetCachedPower(w_p.e, K);
|
|
351
|
+
W = DiyFp_multiply(Normalize(v), c_mk);
|
|
352
|
+
Wp = DiyFp_multiply(w_p, c_mk);
|
|
353
|
+
Wm = DiyFp_multiply(w_m, c_mk);
|
|
354
|
+
Wm.f++;
|
|
355
|
+
Wp.f--;
|
|
356
|
+
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
static __inline const char* GetDigitsLut(void) {
|
|
360
|
+
static const char cDigitsLut[200] = {
|
|
361
|
+
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
|
|
362
|
+
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
|
|
363
|
+
'2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
|
|
364
|
+
'3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
|
|
365
|
+
'4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
|
|
366
|
+
'5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
|
|
367
|
+
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
|
|
368
|
+
'7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
|
|
369
|
+
'8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
|
|
370
|
+
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
|
|
371
|
+
};
|
|
372
|
+
return cDigitsLut;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
static __inline void WriteExponent(int K, char* buffer) {
|
|
376
|
+
if (K < 0) {
|
|
377
|
+
*buffer++ = '-';
|
|
378
|
+
K = -K;
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
*buffer++ = '+';
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (K >= 100) {
|
|
385
|
+
char* d;
|
|
386
|
+
*buffer++ = '0' + (char )(K / 100);
|
|
387
|
+
K %= 100;
|
|
388
|
+
d = (char*)GetDigitsLut() + K * 2;
|
|
389
|
+
*buffer++ = d[0];
|
|
390
|
+
*buffer++ = d[1];
|
|
391
|
+
}
|
|
392
|
+
else if (K >= 10) {
|
|
393
|
+
const char* d = GetDigitsLut() + K * 2;
|
|
394
|
+
*buffer++ = d[0];
|
|
395
|
+
*buffer++ = d[1];
|
|
396
|
+
}
|
|
397
|
+
else
|
|
398
|
+
*buffer++ = '0' + (char )(K);
|
|
399
|
+
|
|
400
|
+
*buffer = '\0';
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
static __inline void Prettify(char* buffer, int length, int k) {
|
|
404
|
+
int i;
|
|
405
|
+
const int kk = length + k; /* 10^(kk-1) <= v < 10^kk */
|
|
406
|
+
|
|
407
|
+
if (length <= kk && kk <= 17) {
|
|
408
|
+
/* 1234e7 -> 12340000000 */
|
|
409
|
+
for (i = length; i < kk; i++)
|
|
410
|
+
buffer[i] = '0';
|
|
411
|
+
buffer[kk] = '\0';
|
|
412
|
+
}
|
|
413
|
+
else if (0 < kk && kk <= 17) {
|
|
414
|
+
/* 1234e-2 -> 12.34 */
|
|
415
|
+
memmove(&buffer[kk + 1], &buffer[kk], length - kk);
|
|
416
|
+
buffer[kk] = '.';
|
|
417
|
+
buffer[length + 1] = '\0';
|
|
418
|
+
}
|
|
419
|
+
else if (-6 < kk && kk <= 0) {
|
|
420
|
+
/* 1234e-6 -> 0.001234 */
|
|
421
|
+
const int offset = 2 - kk;
|
|
422
|
+
memmove(&buffer[offset], &buffer[0], length);
|
|
423
|
+
buffer[0] = '0';
|
|
424
|
+
buffer[1] = '.';
|
|
425
|
+
for (i = 2; i < offset; i++)
|
|
426
|
+
buffer[i] = '0';
|
|
427
|
+
buffer[length + offset] = '\0';
|
|
428
|
+
}
|
|
429
|
+
else if (length == 1) {
|
|
430
|
+
/* 1E30 */
|
|
431
|
+
buffer[1] = 'E';
|
|
432
|
+
WriteExponent(kk - 1, &buffer[2]);
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
/* 1234E30 -> 1.234E33 */
|
|
436
|
+
memmove(&buffer[2], &buffer[1], length - 1);
|
|
437
|
+
buffer[1] = '.';
|
|
438
|
+
buffer[length + 1] = 'E';
|
|
439
|
+
WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
void emyg_dtoa (double value, char* buffer) {
|
|
444
|
+
int length, K;
|
|
445
|
+
/* Not handling NaN and inf */
|
|
446
|
+
assert(!isnan(value));
|
|
447
|
+
assert(!isinf(value));
|
|
448
|
+
|
|
449
|
+
if (value == 0) {
|
|
450
|
+
buffer[0] = '0';
|
|
451
|
+
buffer[1] = '\0';
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
if (value < 0) {
|
|
455
|
+
*buffer++ = '-';
|
|
456
|
+
value = -value;
|
|
457
|
+
}
|
|
458
|
+
Grisu2(value, buffer, &length, &K);
|
|
459
|
+
Prettify(buffer, length, K);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* emyg_dtoa.h
|
|
2
|
+
** Copyright (C) 2015 Doug Currie
|
|
3
|
+
** based on dtoa_milo.h
|
|
4
|
+
** Copyright (C) 2014 Milo Yip
|
|
5
|
+
**
|
|
6
|
+
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
** of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
** in the Software without restriction, including without limitation the rights
|
|
9
|
+
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
** copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
** furnished to do so, subject to the following conditions:
|
|
12
|
+
**
|
|
13
|
+
** The above copyright notice and this permission notice shall be included in
|
|
14
|
+
** all copies or substantial portions of the Software.
|
|
15
|
+
**
|
|
16
|
+
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
** THE SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/* Source from https://github.com/miloyip/dtoa-benchmark */
|
|
26
|
+
void emyg_dtoa (double value, char* buffer);
|