Skip to content

Commit 9e67b47

Browse files
authored
Improve number to string conversions (#400)
integer conversions: - improve `u32toa_radix` and `u64toa_radix`, add `i32toa_radix` - use `i32toa_radix` for small ints in `js_number_toString` floating point conversions (`js_dtoa`): - complete rewrite with fewer calls to `snprintf` - remove `JS_DTOA_FORMAT`, define 4 possible modes for `js_dtoa` - remove the radix argument in `js_dtoa` - merge `js_dtoa1` into `js_dtoa` - add `js_dtoa_infinite` for non finite values - simplify sign handling - handle locale specific decimal point transparently helper function `js_fcvt`: - simplify `js_fcvt`, remove `js_fcvt1`, reduce overhead - round up manually instead of using `fesetround(FE_UPWARD)`. helper function `js_ecvt`: - document `js_ecvt` and `js_ecvt1` behavior - avoid redundant `js_ecvt1` calls in `js_ecvt` - fixed buffer contents, no buffer copies - simplify decimal point handling - round up manually instead of using `fesetround(FE_UPWARD)`. miscellaneous: - remove `CONFIG_PRINTF_RNDN`. This fixes some of the conversion errors on Windows. Updated the tests accordingly - this fixes a v8.sh bug on macOS: `0.5.toFixed(0)` used to produce `0` instead of `1` - add regression tests, update test_conv unit tests - add benchmarks for `toFixed`, `toPrecision` and `toExponential` number methods - benchmarks show all conversions are now 40 to 45% faster (M2)
1 parent 139b51f commit 9e67b47

File tree

6 files changed

+462
-313
lines changed

6 files changed

+462
-313
lines changed

cutils.c

+27-4
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,9 @@ size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_
575575
/* 2 <= base <= 36 */
576576
char const digits36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
577577

578+
#define USE_SPECIAL_RADIX_10 1 // special case base 10 radix conversions
579+
#define USE_SINGLE_CASE_FAST 1 // special case single digit numbers
580+
578581
/* using u32toa_shift variant */
579582

580583
#define gen_digit(buf, c) if (is_be()) \
@@ -613,11 +616,13 @@ size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
613616

614617
size_t u32toa(char buf[minimum_length(11)], uint32_t n)
615618
{
619+
#ifdef USE_SINGLE_CASE_FAST /* 10% */
616620
if (n < 10) {
617621
buf[0] = (char)('0' + n);
618622
buf[1] = '\0';
619623
return 1;
620624
}
625+
#endif
621626
#define TEN_POW_7 10000000
622627
if (n >= TEN_POW_7) {
623628
uint32_t quo = n / TEN_POW_7;
@@ -679,6 +684,8 @@ static uint8_t const radix_shift[64] = {
679684

680685
size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
681686
{
687+
int shift;
688+
682689
#ifdef USE_SPECIAL_RADIX_10
683690
if (likely(base == 10))
684691
return u32toa(buf, n);
@@ -688,13 +695,13 @@ size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
688695
buf[1] = '\0';
689696
return 1;
690697
}
691-
int shift = radix_shift[base & 63];
698+
shift = radix_shift[base & 63];
692699
if (shift) {
693700
uint32_t mask = (1 << shift) - 1;
694701
size_t len = (32 - clz32(n) + shift - 1) / shift;
695702
size_t last = n & mask;
696-
n /= base;
697703
char *end = buf + len;
704+
n >>= shift;
698705
*end-- = '\0';
699706
*end-- = digits36[last];
700707
while (n >= base) {
@@ -728,11 +735,13 @@ size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
728735

729736
size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
730737
{
738+
int shift;
739+
731740
#ifdef USE_SPECIAL_RADIX_10
732741
if (likely(base == 10))
733742
return u64toa(buf, n);
734743
#endif
735-
int shift = radix_shift[base & 63];
744+
shift = radix_shift[base & 63];
736745
if (shift) {
737746
if (n < base) {
738747
buf[0] = digits36[n];
@@ -742,8 +751,8 @@ size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
742751
uint64_t mask = (1 << shift) - 1;
743752
size_t len = (64 - clz64(n) + shift - 1) / shift;
744753
size_t last = n & mask;
745-
n /= base;
746754
char *end = buf + len;
755+
n >>= shift;
747756
*end-- = '\0';
748757
*end-- = digits36[last];
749758
while (n >= base) {
@@ -777,6 +786,15 @@ size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
777786
}
778787
}
779788

789+
size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned int base)
790+
{
791+
if (likely(n >= 0))
792+
return u32toa_radix(buf, n, base);
793+
794+
buf[0] = '-';
795+
return 1 + u32toa_radix(buf + 1, -(uint32_t)n, base);
796+
}
797+
780798
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
781799
{
782800
if (likely(n >= 0))
@@ -786,6 +804,11 @@ size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
786804
return 1 + u64toa_radix(buf + 1, -(uint64_t)n, base);
787805
}
788806

807+
#undef gen_digit
808+
#undef TEN_POW_7
809+
#undef USE_SPECIAL_RADIX_10
810+
#undef USE_SINGLE_CASE_FAST
811+
789812
/*---- sorting with opaque argument ----*/
790813

791814
typedef void (*exchange_f)(void *a, void *b, size_t size);

cutils.h

+1
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ size_t i32toa(char buf[minimum_length(12)], int32_t n);
463463
size_t u64toa(char buf[minimum_length(21)], uint64_t n);
464464
size_t i64toa(char buf[minimum_length(22)], int64_t n);
465465
size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned int base);
466+
size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned base);
466467
size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned int base);
467468
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base);
468469

0 commit comments

Comments
 (0)