1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1997-2013. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: -module(num_bif_SUITE). 21: 22: -include_lib("test_server/include/test_server.hrl"). 23: 24: %% Tests the BIFs: 25: %% abs/1 26: %% float/1 27: %% float_to_list/1 28: %% float_to_list/2 29: %% integer_to_list/1 30: %% list_to_float/1 31: %% list_to_integer/1 32: %% round/1 33: %% trunc/1 34: %% integer_to_binary/1 35: %% integer_to_binary/2 36: %% binary_to_integer/1 37: 38: -export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1, 39: init_per_group/2, end_per_group/2, t_abs/1, t_float/1, 40: t_float_to_string/1, t_integer_to_string/1, 41: t_string_to_integer/1, 42: t_string_to_float_safe/1, t_string_to_float_risky/1, 43: t_round/1, t_trunc/1 44: ]). 45: 46: suite() -> [{ct_hooks,[ts_install_cth]}]. 47: 48: all() -> 49: [t_abs, t_float, t_float_to_string, t_integer_to_string, 50: {group, t_string_to_float}, t_string_to_integer, t_round, 51: t_trunc]. 52: 53: groups() -> 54: [{t_string_to_float, [], 55: [t_string_to_float_safe, t_string_to_float_risky]}]. 56: 57: init_per_suite(Config) -> 58: Config. 59: 60: end_per_suite(_Config) -> 61: ok. 62: 63: init_per_group(_GroupName, Config) -> 64: Config. 65: 66: end_per_group(_GroupName, Config) -> 67: Config. 68: 69: 70: t_abs(Config) when is_list(Config) -> 71: %% Floats. 72: 5.5 = abs(id(5.5)), 73: 0.0 = abs(id(0.0)), 74: 100.0 = abs(id(-100.0)), 75: 76: %% Integers. 77: 5 = abs(id(5)), 78: 0 = abs(id(0)), 79: 100 = abs(id(-100)), 80: 81: %% The largest smallnum. OTP-3190. 82: X = id((1 bsl 27) - 1), 83: X = abs(X), 84: X = abs(X-1)+1, 85: X = abs(X+1)-1, 86: X = abs(-X), 87: X = abs(-X-1)-1, 88: X = abs(-X+1)+1, 89: 90: %% Bignums. 91: BigNum = id(13984792374983749), 92: BigNum = abs(BigNum), 93: BigNum = abs(-BigNum), 94: ok. 95: 96: t_float(Config) when is_list(Config) -> 97: 0.0 = float(id(0)), 98: 2.5 = float(id(2.5)), 99: 0.0 = float(id(0.0)), 100: -100.55 = float(id(-100.55)), 101: 42.0 = float(id(42)), 102: -100.0 = float(id(-100)), 103: 104: %% Bignums. 105: 4294967305.0 = float(id(4294967305)), 106: -4294967305.0 = float(id(-4294967305)), 107: 108: %% Extremly big bignums. 109: Big = id(list_to_integer(id(lists:duplicate(2000, $1)))), 110: {'EXIT', {badarg, _}} = (catch float(Big)), 111: 112: ok. 113: 114: 115: %% Tests float_to_list/1, float_to_list/2, float_to_binary/1, float_to_binary/2 116: 117: t_float_to_string(Config) when is_list(Config) -> 118: test_fts("0.00000000000000000000e+00", 0.0), 119: test_fts("2.50000000000000000000e+01", 25.0), 120: test_fts("2.50000000000000000000e+00", 2.5), 121: test_fts("2.50000000000000000000e-01", 0.25), 122: test_fts("-3.50000000000000000000e+17", -350.0e15), 123: test_fts("1.00000000000000000000e+00",1.0), 124: test_fts("1.00000000000000000000e+00",1.0, []), 125: test_fts("-1.00000000000000000000e+00",-1.0, []), 126: test_fts("-1.00000000000000000000",-1.0, [{decimals, 20}]), 127: {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, -1}])), 128: {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, 254}])), 129: {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{scientific, 250}])), 130: {'EXIT', {badarg, _}} = (catch float_to_list(1.0e+300, [{decimals, 1}])), 131: {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{decimals, -1}])), 132: {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{decimals, 254}])), 133: {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{scientific, 250}])), 134: {'EXIT', {badarg, _}} = (catch float_to_binary(1.0e+300, [{decimals, 1}])), 135: test_fts("1.0e+300",1.0e+300, [{scientific, 1}]), 136: test_fts("1.0",1.0, [{decimals, 249}, compact]), 137: test_fts("1",1.0,[{decimals,0}]), 138: test_fts("2",1.9,[{decimals,0}]), 139: test_fts("123456789012345680.0",123456789012345678.0, 140: [{decimals, 236}, compact]), 141: {'EXIT', {badarg, _}} = (catch float_to_list( 142: 123456789012345678.0, [{decimals, 237}])), 143: {'EXIT', {badarg, _}} = (catch float_to_binary( 144: 123456789012345678.0, [{decimals, 237}])), 145: test_fts("1." ++ string:copies("0", 249) ++ "e+00", 146: 1.0, [{scientific, 249}, compact]), 147: 148: X1 = float_to_list(1.0), 149: X2 = float_to_list(1.0, [{scientific, 20}]), 150: X1 = X2, 151: 152: Y1 = float_to_binary(1.0), 153: Y2 = float_to_binary(1.0, [{scientific, 20}]), 154: Y1 = Y2, 155: 156: test_fts("1.000e+00",1.0, [{scientific, 3}]), 157: test_fts("1.000",1.0, [{decimals, 3}]), 158: test_fts("1.0",1.0, [{decimals, 1}]), 159: test_fts("1.0",1.0, [{decimals, 3}, compact]), 160: test_fts("1.12",1.123, [{decimals, 2}]), 161: test_fts("1.123",1.123, [{decimals, 3}]), 162: test_fts("1.123",1.123, [{decimals, 3}, compact]), 163: test_fts("1.1230",1.123, [{decimals, 4}]), 164: test_fts("1.12300",1.123, [{decimals, 5}]), 165: test_fts("1.123",1.123, [{decimals, 5}, compact]), 166: test_fts("1.1234",1.1234,[{decimals, 6}, compact]), 167: test_fts("1.01",1.005, [{decimals, 2}]), 168: test_fts("-1.01",-1.005,[{decimals, 2}]), 169: test_fts("0.999",0.999, [{decimals, 3}]), 170: test_fts("-0.999",-0.999,[{decimals, 3}]), 171: test_fts("1.0",0.999, [{decimals, 2}, compact]), 172: test_fts("-1.0",-0.999,[{decimals, 2}, compact]), 173: test_fts("0.5",0.5, [{decimals, 1}]), 174: test_fts("-0.5",-0.5, [{decimals, 1}]), 175: "2.333333" = erlang:float_to_list(7/3, [{decimals, 6}, compact]), 176: "2.333333" = erlang:float_to_list(7/3, [{decimals, 6}]), 177: <<"2.333333">> = erlang:float_to_binary(7/3, [{decimals, 6}, compact]), 178: <<"2.333333">> = erlang:float_to_binary(7/3, [{decimals, 6}]), 179: test_fts("0.00000000000000000000e+00",0.0, [compact]), 180: test_fts("0.0",0.0, [{decimals, 10}, compact]), 181: test_fts("123000000000000000000.0",1.23e20, [{decimals, 10}, compact]), 182: test_fts("1.2300000000e+20",1.23e20, [{scientific, 10}, compact]), 183: test_fts("1.23000000000000000000e+20",1.23e20, []), 184: ok. 185: 186: test_fts(Expect, Float) -> 187: Expect = float_to_list(Float), 188: BinExpect = list_to_binary(Expect), 189: BinExpect = float_to_binary(Float). 190: 191: test_fts(Expect, Float, Args) -> 192: Expect = float_to_list(Float,Args), 193: BinExpect = list_to_binary(Expect), 194: BinExpect = float_to_binary(Float,Args). 195: 196: 197: %% Tests list_to_float/1. 198: 199: t_string_to_float_safe(Config) when is_list(Config) -> 200: test_stf(0.0,"0.0"), 201: test_stf(0.0,"-0.0"), 202: test_stf(0.5,"0.5"), 203: test_stf(-0.5,"-0.5"), 204: test_stf(100.0,"1.0e2"), 205: test_stf(127.5,"127.5"), 206: test_stf(-199.5,"-199.5"), 207: 208: {'EXIT',{badarg,_}} = (catch list_to_float(id("0"))), 209: {'EXIT',{badarg,_}} = (catch list_to_float(id("0..0"))), 210: {'EXIT',{badarg,_}} = (catch list_to_float(id("0e12"))), 211: {'EXIT',{badarg,_}} = (catch list_to_float(id("--0.0"))), 212: {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0">>))), 213: {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0..0">>))), 214: {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0e12">>))), 215: {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"--0.0">>))), 216: 217: UBin = <<0:3,(id(<<"0.0">>))/binary,0:5>>, 218: <<_:3,UnAlignedBin:3/binary,0:5>> = id(UBin), 219: 0.0 = binary_to_float(UnAlignedBin), 220: 221: ABin = <<0:8,(id(<<"1.0">>))/binary,0:8>>, 222: <<_:8,AlignedBin:3/binary,0:8>> = id(ABin), 223: 1.0 = binary_to_float(AlignedBin), 224: 225: ok. 226: 227: %% This might crash the emulator... 228: %% (Known to crash the Unix version of Erlang 4.4.1) 229: 230: t_string_to_float_risky(Config) when is_list(Config) -> 231: Many_Ones = lists:duplicate(25000, id($1)), 232: id(list_to_float("2."++Many_Ones)), 233: {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)), 234: 235: id(binary_to_float(list_to_binary("2."++Many_Ones))), 236: {'EXIT', {badarg, _}} = (catch binary_to_float( 237: list_to_binary("2"++Many_Ones))), 238: ok. 239: 240: test_stf(Expect,List) -> 241: Expect = list_to_float(List), 242: Bin = list_to_binary(List), 243: Expect = binary_to_float(Bin). 244: 245: %% Tests round/1. 246: 247: t_round(Config) when is_list(Config) -> 248: 0 = round(id(0.0)), 249: 0 = round(id(0.4)), 250: 1 = round(id(0.5)), 251: 0 = round(id(-0.4)), 252: -1 = round(id(-0.5)), 253: 255 = round(id(255.3)), 254: 256 = round(id(255.6)), 255: -1033 = round(id(-1033.3)), 256: -1034 = round(id(-1033.6)), 257: 258: % OTP-3722: 259: X = id((1 bsl 27) - 1), 260: MX = -X, 261: MXm1 = -X-1, 262: MXp1 = -X+1, 263: F = id(X + 0.0), 264: X = round(F), 265: X = round(F+1)-1, 266: X = round(F-1)+1, 267: MX = round(-F), 268: MXm1 = round(-F-1), 269: MXp1 = round(-F+1), 270: 271: X = round(F+0.1), 272: X = round(F+1+0.1)-1, 273: X = round(F-1+0.1)+1, 274: MX = round(-F+0.1), 275: MXm1 = round(-F-1+0.1), 276: MXp1 = round(-F+1+0.1), 277: 278: X = round(F-0.1), 279: X = round(F+1-0.1)-1, 280: X = round(F-1-0.1)+1, 281: MX = round(-F-0.1), 282: MXm1 = round(-F-1-0.1), 283: MXp1 = round(-F+1-0.1), 284: 285: 0.5 = abs(round(F+0.5)-(F+0.5)), 286: 0.5 = abs(round(F-0.5)-(F-0.5)), 287: 0.5 = abs(round(-F-0.5)-(-F-0.5)), 288: 0.5 = abs(round(-F+0.5)-(-F+0.5)), 289: 290: %% Bignums. 291: 4294967296 = round(id(4294967296.1)), 292: 4294967297 = round(id(4294967296.9)), 293: -4294967296 = -round(id(4294967296.1)), 294: -4294967297 = -round(id(4294967296.9)), 295: ok. 296: 297: t_trunc(Config) when is_list(Config) -> 298: 0 = trunc(id(0.0)), 299: 5 = trunc(id(5.3333)), 300: -10 = trunc(id(-10.978987)), 301: 302: % The largest smallnum, converted to float (OTP-3722): 303: X = id((1 bsl 27) - 1), 304: F = id(X + 0.0), 305: io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n", 306: [X, X, binary_to_list(term_to_binary(X)), 307: F, F, binary_to_list(term_to_binary(F)), 308: trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]), 309: X = trunc(F), 310: X = trunc(F+1)-1, 311: X = trunc(F-1)+1, 312: X = -trunc(-F), 313: X = -trunc(-F-1)-1, 314: X = -trunc(-F+1)+1, 315: 316: %% Bignums. 317: 4294967305 = trunc(id(4294967305.7)), 318: -4294967305 = trunc(id(-4294967305.7)), 319: ok. 320: 321: 322: %% Tests integer_to_binary/1. 323: 324: t_integer_to_string(Config) when is_list(Config) -> 325: test_its("0",0), 326: test_its("42",42), 327: test_its("-42",-42), 328: test_its("32768",32768), 329: test_its("268435455",268435455), 330: test_its("-268435455",-268435455), 331: test_its("123456932798748738738",123456932798748738738), 332: 333: %% 1 bsl 33, just beyond 32 bit 334: test_its("8589934592",8589934592), 335: test_its("-8589934592",-8589934592), 336: %% 1 bsl 65, just beyond 64 bit 337: test_its("36893488147419103232",36893488147419103232), 338: test_its("-36893488147419103232",-36893488147419103232), 339: 340: %% Bignums. 341: BigBin = id(list_to_binary(lists:duplicate(2000, id($1)))), 342: Big = erlang:binary_to_integer(BigBin), 343: BigBin = erlang:integer_to_binary(Big), 344: 345: %% Invalid types 346: lists:foreach(fun(Value) -> 347: {'EXIT', {badarg, _}} = 348: (catch erlang:integer_to_binary(Value)), 349: {'EXIT', {badarg, _}} = 350: (catch erlang:integer_to_list(Value)) 351: end,[atom,1.2,0.0,[$1,[$2]]]), 352: 353: %% Base-2 integers 354: test_its("0", 0, 2), 355: test_its("1", 1, 2), 356: test_its("110110", 54, 2), 357: test_its("-1000000", -64, 2), 358: %% Base-16 integers 359: test_its("0", 0, 16), 360: test_its("A", 10, 16), 361: test_its("D4BE", 54462, 16), 362: test_its("-D4BE", -54462, 16), 363: 364: lists:foreach(fun(Value) -> 365: {'EXIT', {badarg, _}} = 366: (catch erlang:integer_to_binary(Value, 8)), 367: {'EXIT', {badarg, _}} = 368: (catch erlang:integer_to_list(Value, 8)) 369: end,[atom,1.2,0.0,[$1,[$2]]]), 370: 371: ok. 372: 373: test_its(List,Int) -> 374: Int = list_to_integer(List), 375: Int = binary_to_integer(list_to_binary(List)). 376: 377: test_its(List,Int,Base) -> 378: Int = list_to_integer(List, Base), 379: Int = binary_to_integer(list_to_binary(List), Base). 380: 381: %% Tests binary_to_integer/1. 382: 383: t_string_to_integer(Config) when is_list(Config) -> 384: 0 = erlang:binary_to_integer(id(<<"00">>)), 385: 0 = erlang:binary_to_integer(id(<<"-0">>)), 386: 0 = erlang:binary_to_integer(id(<<"+0">>)), 387: 388: test_sti(0), 389: test_sti(1), 390: test_sti(-1), 391: test_sti(42), 392: test_sti(-12), 393: test_sti(32768), 394: test_sti(268435455), 395: test_sti(-268435455), 396: 397: %% 1 bsl 28 - 1, just before 32 bit bignum 398: test_sti(1 bsl 28 - 1), 399: %% 1 bsl 28, just beyond 32 bit small 400: test_sti(1 bsl 28), 401: %% 1 bsl 33, just beyond 32 bit 402: test_sti(1 bsl 33), 403: %% 1 bsl 60 - 1, just before 64 bit bignum 404: test_sti(1 bsl 60 - 1), 405: %% 1 bsl 60, just beyond 64 bit small 406: test_sti(1 bsl 60), 407: %% 1 bsl 65, just beyond 64 bit 408: test_sti(1 bsl 65), 409: %% Bignums. 410: test_sti(123456932798748738738,16), 411: test_sti(list_to_integer(lists:duplicate(2000, $1))), 412: 413: %% unalign string 414: Str = <<"10">>, 415: UnalignStr = <<0:3, (id(Str))/binary, 0:5>>, 416: <<_:3, SomeStr:2/binary, _:5>> = id(UnalignStr), 417: 10 = erlang:binary_to_integer(SomeStr), 418: 419: %% Invalid types 420: lists:foreach(fun(Value) -> 421: {'EXIT', {badarg, _}} = 422: (catch binary_to_integer(Value)), 423: {'EXIT', {badarg, _}} = 424: (catch erlang:list_to_integer(Value)) 425: end,[atom,1.2,0.0,[$1,[$2]]]), 426: 427: % Default base error cases 428: lists:foreach(fun(Value) -> 429: {'EXIT', {badarg, _}} = 430: (catch erlang:binary_to_integer( 431: list_to_binary(Value))), 432: {'EXIT', {badarg, _}} = 433: (catch erlang:list_to_integer(Value)) 434: end,["1.0"," 1"," -1",""]), 435: 436: % Custom base error cases 437: lists:foreach(fun({Value,Base}) -> 438: {'EXIT', {badarg, _}} = 439: (catch binary_to_integer( 440: list_to_binary(Value),Base)), 441: {'EXIT', {badarg, _}} = 442: (catch erlang:list_to_integer(Value,Base)) 443: end,[{" 1",1},{" 1",37},{"2",2},{"C",11}, 444: {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111z",16}, 445: {"1z111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",16}, 446: {"111z11111111",16}]), 447: 448: ok. 449: 450: test_sti(Num) -> 451: [begin 452: io:format("Testing ~p:~p",[Num,Base]), 453: test_sti(Num,Base) 454: end|| Base <- lists:seq(2,36)]. 455: 456: test_sti(Num,Base) -> 457: Num = list_to_integer(int2list(Num,Base),Base), 458: Num = -1*list_to_integer(int2list(Num*-1,Base),Base), 459: Num = binary_to_integer(int2bin(Num,Base),Base), 460: Num = -1*binary_to_integer(int2bin(Num*-1,Base),Base). 461: 462: % Calling this function (which is not supposed to be inlined) prevents 463: % the compiler from calculating the answer, so we don't test the compiler 464: % instead of the newest runtime system. 465: id(X) -> X. 466: 467: %% Uses the printing library to to integer_to_binary conversions. 468: int2bin(Int,Base) when Base < 37 -> 469: iolist_to_binary(int2list(Int,Base)). 470: 471: int2list(Int,Base) when Base < 37 -> 472: lists:flatten(io_lib:format("~."++integer_to_list(Base)++"B",[Int])).