mirror of
https://github.com/janet-lang/janet
synced 2024-12-24 23:40:27 +00:00
123 lines
4.4 KiB
C
123 lines
4.4 KiB
C
|
/*
|
||
|
* Copyright (c) 2017 Calvin Rose
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
* of this software and associated documentation files (the "Software"), to
|
||
|
* deal in the Software without restriction, including without limitation the
|
||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||
|
* furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||
|
* IN THE SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
/* Use a custom double parser instead of libc's strtod for better portability
|
||
|
* and control. Also, uses a less strict rounding method than ieee to not incur
|
||
|
* the cost of 4000 loc and dependence on arbitary precision arithmetic. There
|
||
|
* is no plan to use arbitrary precision arithmetic for parsing numbers, and a
|
||
|
* formal rounding mode has yet to be chosen (round towards 0 seems
|
||
|
* reasonable).
|
||
|
*
|
||
|
* This version has been modified for much greater flexibility in parsing, such
|
||
|
* as choosing the radix, supporting integer output, and returning DstValues
|
||
|
* directly.
|
||
|
*
|
||
|
* Numbers are of the form [-+]R[rR]I.F[eE&][-+]X where R is the radix, I is
|
||
|
* the integer part, F is the fractional part, and X is the exponent. All
|
||
|
* signs, radix, decimal point, fractional part, and exponent can be ommited.
|
||
|
* The number will be considered and integer if the there is no decimal point
|
||
|
* and no exponent. Any number greater the 2^32-1 or less than -(2^32) will be
|
||
|
* coerced to a double. If there is an error, the function dst_scan_number will
|
||
|
* return a dst nil. The radix is assumed to be 10 if omitted, and the E
|
||
|
* separator for the exponent can only be used when the radix is 10. This is
|
||
|
* because E is a vaid digit in bases 15 or greater. For bases greater than 10,
|
||
|
* the letters are used as digitis. A through Z correspond to the digits 10
|
||
|
* through 35, and the lowercase letters have the same values. The radix number
|
||
|
* is always in base 10. For example, a hexidecimal number could be written
|
||
|
* '16rdeadbeef'. dst_scan_number also supports some c style syntax for
|
||
|
* hexidecimal literals. The previous number could also be written
|
||
|
* '0xdeadbeef'. Note that in this case, the number will actually be a double
|
||
|
* as it will not fit in the range for a signed 32 bit integer. The string
|
||
|
* '0xbeef' would parse to an integer as it is in the range of an int32_t. */
|
||
|
|
||
|
#include "unit.h"
|
||
|
#include <dst/dst.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
DstValue dst_scan_number(const uint8_t *str, int32_t len);
|
||
|
|
||
|
const char *valid_test_strs[] = {
|
||
|
"0",
|
||
|
"-0.0",
|
||
|
"+0",
|
||
|
"123",
|
||
|
"-123",
|
||
|
"aaaaaa",
|
||
|
"+a123",
|
||
|
"0.12312",
|
||
|
"89.12312",
|
||
|
"-123.01231",
|
||
|
"123e10",
|
||
|
"1203412347981232379183.13013248723478932478923478e12",
|
||
|
"120341234798123237918313013248723478932478923478",
|
||
|
"999_999_999_999",
|
||
|
"8r777",
|
||
|
"",
|
||
|
"----",
|
||
|
" ",
|
||
|
"--123",
|
||
|
"0xff",
|
||
|
"0xff.f",
|
||
|
"0xff&-1",
|
||
|
"0xfefefe",
|
||
|
"1926.4823e11",
|
||
|
"0xff_ff_ff_ff",
|
||
|
"0xff_ff_ff_ff_ff_ff",
|
||
|
"2r1010",
|
||
|
"2r10101010001101",
|
||
|
"123a",
|
||
|
"0.1e510",
|
||
|
"4.123123e-308",
|
||
|
"4.123123e-320",
|
||
|
"1e-308",
|
||
|
"1e-309",
|
||
|
"9e-308",
|
||
|
"9e-309",
|
||
|
"919283691283e-309",
|
||
|
"9999e302",
|
||
|
"123.12312.123",
|
||
|
"90.e0.1",
|
||
|
"90.e1",
|
||
|
".e1"
|
||
|
};
|
||
|
|
||
|
int main() {
|
||
|
dst_init();
|
||
|
unsigned i;
|
||
|
for (i = 0; i < (sizeof(valid_test_strs) / sizeof(void *)); i++) {
|
||
|
DstValue out;
|
||
|
double refout;
|
||
|
const uint8_t *str = (const uint8_t *) valid_test_strs[i];
|
||
|
int32_t len = 0; while (str[len]) len++;
|
||
|
|
||
|
refout = strtod(valid_test_strs[i], NULL);
|
||
|
out = dst_scan_number(str, len);
|
||
|
dst_puts(dst_formatc("literal: %s, out: %v, refout: %v\n",
|
||
|
valid_test_strs[i], out, dst_wrap_real(refout)));
|
||
|
|
||
|
}
|
||
|
uint64_t x = 0x07FFFFFFFFFFFFFF;
|
||
|
uint64_t y = 36;
|
||
|
|
||
|
printf("%llu, %llu\n", x, (x * y) / y);
|
||
|
}
|