@@ -5476,30 +5476,55 @@ static Value builtin_fprod(Interpreter* interp, Value* args, int argc, Expr** ar
54765476static Value builtin_round (Interpreter * interp , Value * args , int argc , Expr * * arg_nodes , Env * env , int line , int col ) {
54775477 (void )arg_nodes ; (void )env ;
54785478 EXPECT_NUM (args [0 ], "ROUND" , interp , line , col );
5479-
5479+
5480+ // Signature: ROUND(x, ndigits = 0, mode = "floor")
54805481 int64_t places = 0 ;
5481- if (argc >= 2 ) {
5482+ const char * mode = "floor" ;
5483+
5484+ if (argc >= 2 && args [1 ].type != VAL_NULL ) {
54825485 EXPECT_INT (args [1 ], "ROUND" , interp , line , col );
54835486 places = args [1 ].as .i ;
54845487 }
5485-
5488+ if (argc >= 3 && args [2 ].type != VAL_NULL ) {
5489+ if (args [2 ].type != VAL_STR ) {
5490+ RUNTIME_ERROR (interp , "ROUND expects STR mode" , line , col );
5491+ }
5492+ mode = args [2 ].as .s ;
5493+ if (!mode ) mode = "floor" ;
5494+ }
5495+
5496+ // INT behavior: keep prior semantics (ndigits >= 0 is a no-op; ndigits < 0 rounds toward zero to multiple of 2^(-ndigits)).
54865497 if (args [0 ].type == VAL_INT ) {
54875498 if (places >= 0 ) {
54885499 return value_int (args [0 ].as .i );
54895500 }
5490- // Negative places: round to that power of 2
5491- int64_t factor = 1LL << (- places );
5501+ int64_t shift = - places ;
5502+ if (shift >= 63 ) {
5503+ // 2^shift exceeds int64 range; rounding to such a large factor yields 0.
5504+ return value_int (0 );
5505+ }
5506+ int64_t factor = 1LL << shift ;
54925507 return value_int ((args [0 ].as .i / factor ) * factor );
54935508 }
5494-
5509+
54955510 double val = args [0 ].as .f ;
5496- if (places >= 0 ) {
5497- double factor = (double )(1LL << places );
5498- return value_flt (round (val * factor ) / factor );
5511+ double factor = pow (2.0 , (double )places );
5512+ double scaled = val * factor ;
5513+ double rs ;
5514+
5515+ if (strcmp (mode , "floor" ) == 0 ) {
5516+ rs = floor (scaled );
5517+ } else if (strcmp (mode , "ceiling" ) == 0 || strcmp (mode , "ceil" ) == 0 ) {
5518+ rs = ceil (scaled );
5519+ } else if (strcmp (mode , "zero" ) == 0 ) {
5520+ rs = (scaled >= 0.0 ) ? floor (scaled ) : ceil (scaled );
5521+ } else if (strcmp (mode , "logical" ) == 0 || strcmp (mode , "half-up" ) == 0 ) {
5522+ rs = round (scaled );
54995523 } else {
5500- double factor = (double )(1LL << (- places ));
5501- return value_flt (round (val / factor ) * factor );
5524+ RUNTIME_ERROR (interp , "Unknown ROUND mode" , line , col );
55025525 }
5526+
5527+ return value_flt (rs / factor );
55035528}
55045529
55055530// INV (1/x)
@@ -6702,6 +6727,14 @@ static Value builtin_parallel(Interpreter* interp, Value* args, int argc, Expr**
67026727}
67036728
67046729
6730+ static const char * builtin_params_round [] = {"x" , "ndigits" , "mode" };
6731+ static const char * builtin_params_bytes [] = {"x" , "endian" };
6732+ static const char * builtin_params_split [] = {"s" , "delimiter" };
6733+ static const char * builtin_params_match [] = {"value" , "template" , "typing" , "recurse" , "shape" };
6734+ static const char * builtin_params_readfile [] = {"path" , "coding" };
6735+ static const char * builtin_params_writefile [] = {"data" , "path" , "coding" };
6736+ static const char * builtin_params_pause [] = {"thr" , "seconds" };
6737+
67056738static BuiltinFunction builtins_table [] = {
67066739 // Arithmetic
67076740 {"ADD" , 2 , 2 , builtin_add },
@@ -6720,7 +6753,7 @@ static BuiltinFunction builtins_table[] = {
67206753 {"GCD" , 2 , 2 , builtin_gcd },
67216754 {"LCM" , 2 , 2 , builtin_lcm },
67226755 {"INV" , 1 , 1 , builtin_inv },
6723- {"ROUND" , 1 , 3 , builtin_round },
6756+ {"ROUND" , 1 , 3 , builtin_round , builtin_params_round , 3 },
67246757
67256758 // Coercing arithmetic
67266759 {"IADD" , 2 , 2 , builtin_iadd },
@@ -6783,7 +6816,7 @@ static BuiltinFunction builtins_table[] = {
67836816 {"INT" , 1 , 1 , builtin_int },
67846817 {"FLT" , 1 , 1 , builtin_flt },
67856818 {"STR" , 1 , 1 , builtin_str },
6786- {"BYTES" , 1 , 2 , builtin_bytes },
6819+ {"BYTES" , 1 , 2 , builtin_bytes , builtin_params_bytes , 2 },
67876820 {"SER" , 1 , 1 , builtin_ser },
67886821 {"UNSER" , 1 , 1 , builtin_unser },
67896822
@@ -6804,13 +6837,13 @@ static BuiltinFunction builtins_table[] = {
68046837 {"REPLACE" , 3 , 3 , builtin_replace },
68056838 {"STRIP" , 2 , 2 , builtin_strip },
68066839 {"JOIN" , 1 , -1 , builtin_join },
6807- {"SPLIT" , 1 , 2 , builtin_split },
6840+ {"SPLIT" , 1 , 2 , builtin_split , builtin_params_split , 2 },
68086841 {"IN" , 2 , 2 , builtin_in },
68096842 {"KEYS" , 1 , 1 , builtin_keys },
68106843 {"VALUES" , 1 , 1 , builtin_values },
68116844 {"KEYIN" , 2 , 2 , builtin_keyin },
68126845 {"VALUEIN" , 2 , 2 , builtin_valuein },
6813- {"MATCH" , 2 , 5 , builtin_match },
6846+ {"MATCH" , 2 , 5 , builtin_match , builtin_params_match , 5 },
68146847 {"ILEN" , 1 , 1 , builtin_ilen },
68156848 {"LEN" , 0 , -1 , builtin_len },
68166849
@@ -6819,16 +6852,16 @@ static BuiltinFunction builtins_table[] = {
68196852 {"INPUT" , 0 , 1 , builtin_input },
68206853 {"SHUSH" , 0 , 0 , builtin_shush },
68216854 {"UNSHUSH" , 0 , 0 , builtin_unshush },
6822- {"READFILE" , 1 , 2 , builtin_readfile },
6823- {"WRITEFILE" , 2 , 3 , builtin_writefile },
6855+ {"READFILE" , 1 , 2 , builtin_readfile , builtin_params_readfile , 2 },
6856+ {"WRITEFILE" , 2 , 3 , builtin_writefile , builtin_params_writefile , 3 },
68246857 {"CL" , 1 , 1 , builtin_cl },
68256858 {"EXISTFILE" , 1 , 1 , builtin_existfile },
68266859 {"DELETEFILE" , 1 , 1 , builtin_deletefile },
68276860 {"RUN" , 1 , 1 , builtin_run },
68286861 {"ARGV" , 0 , 0 , builtin_argv },
68296862 {"PARALLEL" , 1 , -1 , builtin_parallel },
68306863 {"AWAIT" , 1 , 1 , builtin_await },
6831- {"PAUSE" , 1 , 2 , builtin_pause },
6864+ {"PAUSE" , 1 , 2 , builtin_pause , builtin_params_pause , 2 },
68326865 {"RESUME" , 1 , 1 , builtin_resume },
68336866 {"PAUSED" , 1 , 1 , builtin_paused },
68346867 {"STOP" , 1 , 1 , builtin_stop },
0 commit comments