| ... | @@ -277,6 +277,8 @@ test { | ... | @@ -277,6 +277,8 @@ test { |
| 277 | std.testing.refAllDecls(@This()); | 277 | std.testing.refAllDecls(@This()); |
| 278 | } | 278 | } |
| 279 | | 279 | |
| | 280 | /// Returns the number of bits in the mantissa of floating point type |
| | 281 | /// T. |
| 280 | pub fn floatMantissaBits(comptime T: type) comptime_int { | 282 | pub fn floatMantissaBits(comptime T: type) comptime_int { |
| 281 | assert(@typeInfo(T) == .Float); | 283 | assert(@typeInfo(T) == .Float); |
| 282 | | 284 | |
| ... | @@ -290,6 +292,8 @@ pub fn floatMantissaBits(comptime T: type) comptime_int { | ... | @@ -290,6 +292,8 @@ pub fn floatMantissaBits(comptime T: type) comptime_int { |
| 290 | }; | 292 | }; |
| 291 | } | 293 | } |
| 292 | | 294 | |
| | 295 | /// Returns the number of bits in the exponent of floating point type |
| | 296 | /// T. |
| 293 | pub fn floatExponentBits(comptime T: type) comptime_int { | 297 | pub fn floatExponentBits(comptime T: type) comptime_int { |
| 294 | assert(@typeInfo(T) == .Float); | 298 | assert(@typeInfo(T) == .Float); |
| 295 | | 299 | |
| ... | @@ -322,20 +326,22 @@ pub fn Min(comptime A: type, comptime B: type) type { | ... | @@ -322,20 +326,22 @@ pub fn Min(comptime A: type, comptime B: type) type { |
| 322 | return @TypeOf(@as(A, 0) + @as(B, 0)); | 326 | return @TypeOf(@as(A, 0) + @as(B, 0)); |
| 323 | } | 327 | } |
| 324 | | 328 | |
| 325 | /// Returns the smaller number. When one of the parameter's type's full range fits in the other, | 329 | /// Returns the smaller number. When one parameter's type's full range |
| 326 | /// the return type is the smaller type. | 330 | /// fits in the other, the return type is the smaller type. |
| 327 | pub fn min(x: anytype, y: anytype) Min(@TypeOf(x), @TypeOf(y)) { | 331 | pub fn min(x: anytype, y: anytype) Min(@TypeOf(x), @TypeOf(y)) { |
| 328 | const Result = Min(@TypeOf(x), @TypeOf(y)); | 332 | const Result = Min(@TypeOf(x), @TypeOf(y)); |
| 329 | if (x < y) { | 333 | if (x < y) { |
| 330 | // TODO Zig should allow this as an implicit cast because x is immutable and in this | 334 | // TODO Zig should allow this as an implicit cast because x is |
| 331 | // scope it is known to fit in the return type. | 335 | // immutable and in this scope it is known to fit in the |
| | 336 | // return type. |
| 332 | switch (@typeInfo(Result)) { | 337 | switch (@typeInfo(Result)) { |
| 333 | .Int => return @intCast(Result, x), | 338 | .Int => return @intCast(Result, x), |
| 334 | else => return x, | 339 | else => return x, |
| 335 | } | 340 | } |
| 336 | } else { | 341 | } else { |
| 337 | // TODO Zig should allow this as an implicit cast because y is immutable and in this | 342 | // TODO Zig should allow this as an implicit cast because y is |
| 338 | // scope it is known to fit in the return type. | 343 | // immutable and in this scope it is known to fit in the |
| | 344 | // return type. |
| 339 | switch (@typeInfo(Result)) { | 345 | switch (@typeInfo(Result)) { |
| 340 | .Int => return @intCast(Result, y), | 346 | .Int => return @intCast(Result, y), |
| 341 | else => return y, | 347 | else => return y, |
| ... | @@ -375,7 +381,7 @@ test "math.min" { | ... | @@ -375,7 +381,7 @@ test "math.min" { |
| 375 | } | 381 | } |
| 376 | } | 382 | } |
| 377 | | 383 | |
| 378 | /// Finds the min of three numbers | 384 | /// Finds the minimum of three numbers. |
| 379 | pub fn min3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) { | 385 | pub fn min3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) { |
| 380 | return min(x, min(y, z)); | 386 | return min(x, min(y, z)); |
| 381 | } | 387 | } |
| ... | @@ -389,6 +395,8 @@ test "math.min3" { | ... | @@ -389,6 +395,8 @@ test "math.min3" { |
| 389 | try testing.expect(min3(@as(i32, 2), @as(i32, 1), @as(i32, 0)) == 0); | 395 | try testing.expect(min3(@as(i32, 2), @as(i32, 1), @as(i32, 0)) == 0); |
| 390 | } | 396 | } |
| 391 | | 397 | |
| | 398 | /// Returns the maximum of two numbers. Return type is the one with the |
| | 399 | /// larger range. |
| 392 | pub fn max(x: anytype, y: anytype) @TypeOf(x, y) { | 400 | pub fn max(x: anytype, y: anytype) @TypeOf(x, y) { |
| 393 | return if (x > y) x else y; | 401 | return if (x > y) x else y; |
| 394 | } | 402 | } |
| ... | @@ -398,7 +406,7 @@ test "math.max" { | ... | @@ -398,7 +406,7 @@ test "math.max" { |
| 398 | try testing.expect(max(@as(i32, 2), @as(i32, -1)) == 2); | 406 | try testing.expect(max(@as(i32, 2), @as(i32, -1)) == 2); |
| 399 | } | 407 | } |
| 400 | | 408 | |
| 401 | /// Finds the max of three numbers | 409 | /// Finds the maximum of three numbers. |
| 402 | pub fn max3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) { | 410 | pub fn max3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) { |
| 403 | return max(x, max(y, z)); | 411 | return max(x, max(y, z)); |
| 404 | } | 412 | } |
| ... | @@ -412,6 +420,7 @@ test "math.max3" { | ... | @@ -412,6 +420,7 @@ test "math.max3" { |
| 412 | try testing.expect(max3(@as(i32, 2), @as(i32, 1), @as(i32, 0)) == 2); | 420 | try testing.expect(max3(@as(i32, 2), @as(i32, 1), @as(i32, 0)) == 2); |
| 413 | } | 421 | } |
| 414 | | 422 | |
| | 423 | /// Limit val to the inclusive range [lower, upper]. |
| 415 | pub fn clamp(val: anytype, lower: anytype, upper: anytype) @TypeOf(val, lower, upper) { | 424 | pub fn clamp(val: anytype, lower: anytype, upper: anytype) @TypeOf(val, lower, upper) { |
| 416 | assert(lower <= upper); | 425 | assert(lower <= upper); |
| 417 | return max(lower, min(val, upper)); | 426 | return max(lower, min(val, upper)); |
| ... | @@ -433,17 +442,20 @@ test "math.clamp" { | ... | @@ -433,17 +442,20 @@ test "math.clamp" { |
| 433 | try testing.expect(std.math.clamp(i, 0, 1) == 1); | 442 | try testing.expect(std.math.clamp(i, 0, 1) == 1); |
| 434 | } | 443 | } |
| 435 | | 444 | |
| | 445 | /// Returns the product of a and b. Returns an error on overflow. |
| 436 | pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) { | 446 | pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) { |
| 437 | var answer: T = undefined; | 447 | var answer: T = undefined; |
| 438 | return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer; | 448 | return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 439 | } | 449 | } |
| 440 | | 450 | |
| | 451 | /// Returns the sum of a and b. Returns an error on overflow. |
| 441 | pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) { | 452 | pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) { |
| 442 | if (T == comptime_int) return a + b; | 453 | if (T == comptime_int) return a + b; |
| 443 | var answer: T = undefined; | 454 | var answer: T = undefined; |
| 444 | return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; | 455 | return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 445 | } | 456 | } |
| 446 | | 457 | |
| | 458 | /// Returns a - b, or an error on overflow. |
| 447 | pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) { | 459 | pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) { |
| 448 | var answer: T = undefined; | 460 | var answer: T = undefined; |
| 449 | return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer; | 461 | return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| ... | @@ -453,6 +465,8 @@ pub fn negate(x: anytype) !@TypeOf(x) { | ... | @@ -453,6 +465,8 @@ pub fn negate(x: anytype) !@TypeOf(x) { |
| 453 | return sub(@TypeOf(x), 0, x); | 465 | return sub(@TypeOf(x), 0, x); |
| 454 | } | 466 | } |
| 455 | | 467 | |
| | 468 | /// Shifts a left by shift_amt. Returns an error on overflow. shift_amt |
| | 469 | /// is unsigned. |
| 456 | pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { | 470 | pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { |
| 457 | var answer: T = undefined; | 471 | var answer: T = undefined; |
| 458 | return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer; | 472 | return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer; |
| ... | @@ -538,8 +552,8 @@ test "math.shr" { | ... | @@ -538,8 +552,8 @@ test "math.shr" { |
| 538 | try testing.expect(shr(std.meta.Vector(1, u32), std.meta.Vector(1, u32){42}, 33)[0] == 0); | 552 | try testing.expect(shr(std.meta.Vector(1, u32), std.meta.Vector(1, u32){42}, 33)[0] == 0); |
| 539 | } | 553 | } |
| 540 | | 554 | |
| 541 | /// Rotates right. Only unsigned values can be rotated. | 555 | /// Rotates right. Only unsigned values can be rotated. Negative shift |
| 542 | /// Negative shift values results in shift modulo the bit count. | 556 | /// values result in shift modulo the bit count. |
| 543 | pub fn rotr(comptime T: type, x: T, r: anytype) T { | 557 | pub fn rotr(comptime T: type, x: T, r: anytype) T { |
| 544 | if (@typeInfo(T) == .Vector) { | 558 | if (@typeInfo(T) == .Vector) { |
| 545 | const C = @typeInfo(T).Vector.child; | 559 | const C = @typeInfo(T).Vector.child; |
| ... | @@ -566,8 +580,8 @@ test "math.rotr" { | ... | @@ -566,8 +580,8 @@ test "math.rotr" { |
| 566 | try testing.expect(rotr(std.meta.Vector(1, u32), std.meta.Vector(1, u32){1}, @as(isize, -1))[0] == @as(u32, 1) << 1); | 580 | try testing.expect(rotr(std.meta.Vector(1, u32), std.meta.Vector(1, u32){1}, @as(isize, -1))[0] == @as(u32, 1) << 1); |
| 567 | } | 581 | } |
| 568 | | 582 | |
| 569 | /// Rotates left. Only unsigned values can be rotated. | 583 | /// Rotates left. Only unsigned values can be rotated. Negative shift |
| 570 | /// Negative shift values results in shift modulo the bit count. | 584 | /// values result in shift modulo the bit count. |
| 571 | pub fn rotl(comptime T: type, x: T, r: anytype) T { | 585 | pub fn rotl(comptime T: type, x: T, r: anytype) T { |
| 572 | if (@typeInfo(T) == .Vector) { | 586 | if (@typeInfo(T) == .Vector) { |
| 573 | const C = @typeInfo(T).Vector.child; | 587 | const C = @typeInfo(T).Vector.child; |
| ... | @@ -594,6 +608,8 @@ test "math.rotl" { | ... | @@ -594,6 +608,8 @@ test "math.rotl" { |
| 594 | try testing.expect(rotl(std.meta.Vector(1, u32), std.meta.Vector(1, u32){1 << 31}, @as(isize, -1))[0] == @as(u32, 1) << 30); | 608 | try testing.expect(rotl(std.meta.Vector(1, u32), std.meta.Vector(1, u32){1 << 31}, @as(isize, -1))[0] == @as(u32, 1) << 30); |
| 595 | } | 609 | } |
| 596 | | 610 | |
| | 611 | /// Returns an unsigned int type that can hold the number of bits in T |
| | 612 | /// - 1. Suitable for 0-based bit indices of T. |
| 597 | pub fn Log2Int(comptime T: type) type { | 613 | pub fn Log2Int(comptime T: type) type { |
| 598 | // comptime ceil log2 | 614 | // comptime ceil log2 |
| 599 | comptime var count = 0; | 615 | comptime var count = 0; |
| ... | @@ -605,6 +621,7 @@ pub fn Log2Int(comptime T: type) type { | ... | @@ -605,6 +621,7 @@ pub fn Log2Int(comptime T: type) type { |
| 605 | return std.meta.Int(.unsigned, count); | 621 | return std.meta.Int(.unsigned, count); |
| 606 | } | 622 | } |
| 607 | | 623 | |
| | 624 | /// Returns an unsigned int type that can hold the number of bits in T. |
| 608 | pub fn Log2IntCeil(comptime T: type) type { | 625 | pub fn Log2IntCeil(comptime T: type) type { |
| 609 | // comptime ceil log2 | 626 | // comptime ceil log2 |
| 610 | comptime var count = 0; | 627 | comptime var count = 0; |
| ... | @@ -616,6 +633,7 @@ pub fn Log2IntCeil(comptime T: type) type { | ... | @@ -616,6 +633,7 @@ pub fn Log2IntCeil(comptime T: type) type { |
| 616 | return std.meta.Int(.unsigned, count); | 633 | return std.meta.Int(.unsigned, count); |
| 617 | } | 634 | } |
| 618 | | 635 | |
| | 636 | /// Returns the smallest integer type that can hold both from and to. |
| 619 | pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type { | 637 | pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type { |
| 620 | assert(from <= to); | 638 | assert(from <= to); |
| 621 | if (from == 0 and to == 0) { | 639 | if (from == 0 and to == 0) { |
| ... | @@ -691,6 +709,8 @@ fn testOverflow() !void { | ... | @@ -691,6 +709,8 @@ fn testOverflow() !void { |
| 691 | try testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000); | 709 | try testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000); |
| 692 | } | 710 | } |
| 693 | | 711 | |
| | 712 | /// Returns the absolute value of x, where x is a value of an integer |
| | 713 | /// type. |
| 694 | pub fn absInt(x: anytype) !@TypeOf(x) { | 714 | pub fn absInt(x: anytype) !@TypeOf(x) { |
| 695 | const T = @TypeOf(x); | 715 | const T = @TypeOf(x); |
| 696 | comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt | 716 | comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt |
| ... | @@ -724,6 +744,8 @@ fn testAbsFloat() !void { | ... | @@ -724,6 +744,8 @@ fn testAbsFloat() !void { |
| 724 | try testing.expect(absFloat(@as(f32, 10.05)) == 10.05); | 744 | try testing.expect(absFloat(@as(f32, 10.05)) == 10.05); |
| 725 | } | 745 | } |
| 726 | | 746 | |
| | 747 | /// Divide numerator by denominator, rounding toward zero. Returns an |
| | 748 | /// error on overflow or when denominator is zero. |
| 727 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { | 749 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { |
| 728 | @setRuntimeSafety(false); | 750 | @setRuntimeSafety(false); |
| 729 | if (denominator == 0) return error.DivisionByZero; | 751 | if (denominator == 0) return error.DivisionByZero; |
| ... | @@ -745,6 +767,9 @@ fn testDivTrunc() !void { | ... | @@ -745,6 +767,9 @@ fn testDivTrunc() !void { |
| 745 | try testing.expect((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0); | 767 | try testing.expect((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0); |
| 746 | } | 768 | } |
| 747 | | 769 | |
| | 770 | /// Divide numerator by denominator, rounding toward negative |
| | 771 | /// infinity. Returns an error on overflow or when denominator is |
| | 772 | /// zero. |
| 748 | pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { | 773 | pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { |
| 749 | @setRuntimeSafety(false); | 774 | @setRuntimeSafety(false); |
| 750 | if (denominator == 0) return error.DivisionByZero; | 775 | if (denominator == 0) return error.DivisionByZero; |
| ... | @@ -766,6 +791,9 @@ fn testDivFloor() !void { | ... | @@ -766,6 +791,9 @@ fn testDivFloor() !void { |
| 766 | try testing.expect((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0); | 791 | try testing.expect((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0); |
| 767 | } | 792 | } |
| 768 | | 793 | |
| | 794 | /// Divide numerator by denominator, rounding toward positive |
| | 795 | /// infinity. Returns an error on overflow or when denominator is |
| | 796 | /// zero. |
| 769 | pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T { | 797 | pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T { |
| 770 | @setRuntimeSafety(false); | 798 | @setRuntimeSafety(false); |
| 771 | if (comptime std.meta.trait.isNumber(T) and denominator == 0) return error.DivisionByZero; | 799 | if (comptime std.meta.trait.isNumber(T) and denominator == 0) return error.DivisionByZero; |
| ... | @@ -819,6 +847,8 @@ fn testDivCeil() !void { | ... | @@ -819,6 +847,8 @@ fn testDivCeil() !void { |
| 819 | try testing.expectError(error.DivisionByZero, divCeil(comptime_float, 23.0, 0.0)); | 847 | try testing.expectError(error.DivisionByZero, divCeil(comptime_float, 23.0, 0.0)); |
| 820 | } | 848 | } |
| 821 | | 849 | |
| | 850 | /// Divide numerator by denominator. Return an error if quotient is |
| | 851 | /// not an integer, denominator is zero, or on overflow. |
| 822 | pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { | 852 | pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { |
| 823 | @setRuntimeSafety(false); | 853 | @setRuntimeSafety(false); |
| 824 | if (denominator == 0) return error.DivisionByZero; | 854 | if (denominator == 0) return error.DivisionByZero; |
| ... | @@ -844,6 +874,9 @@ fn testDivExact() !void { | ... | @@ -844,6 +874,9 @@ fn testDivExact() !void { |
| 844 | try testing.expectError(error.UnexpectedRemainder, divExact(f32, 5.0, 2.0)); | 874 | try testing.expectError(error.UnexpectedRemainder, divExact(f32, 5.0, 2.0)); |
| 845 | } | 875 | } |
| 846 | | 876 | |
| | 877 | /// Returns numerator modulo denominator, or an error if denominator is |
| | 878 | /// zero or negative. Negative numerators never result in negative |
| | 879 | /// return values. |
| 847 | pub fn mod(comptime T: type, numerator: T, denominator: T) !T { | 880 | pub fn mod(comptime T: type, numerator: T, denominator: T) !T { |
| 848 | @setRuntimeSafety(false); | 881 | @setRuntimeSafety(false); |
| 849 | if (denominator == 0) return error.DivisionByZero; | 882 | if (denominator == 0) return error.DivisionByZero; |
| ... | @@ -867,6 +900,9 @@ fn testMod() !void { | ... | @@ -867,6 +900,9 @@ fn testMod() !void { |
| 867 | try testing.expectError(error.DivisionByZero, mod(f32, 10, 0)); | 900 | try testing.expectError(error.DivisionByZero, mod(f32, 10, 0)); |
| 868 | } | 901 | } |
| 869 | | 902 | |
| | 903 | /// Returns the remainder when numerator is divided by denominator, or |
| | 904 | /// an error if denominator is zero or negative. Negative numerators |
| | 905 | /// can give negative results. |
| 870 | pub fn rem(comptime T: type, numerator: T, denominator: T) !T { | 906 | pub fn rem(comptime T: type, numerator: T, denominator: T) !T { |
| 871 | @setRuntimeSafety(false); | 907 | @setRuntimeSafety(false); |
| 872 | if (denominator == 0) return error.DivisionByZero; | 908 | if (denominator == 0) return error.DivisionByZero; |
| ... | @@ -989,6 +1025,8 @@ pub fn isPowerOfTwo(v: anytype) bool { | ... | @@ -989,6 +1025,8 @@ pub fn isPowerOfTwo(v: anytype) bool { |
| 989 | return (v & (v - 1)) == 0; | 1025 | return (v & (v - 1)) == 0; |
| 990 | } | 1026 | } |
| 991 | | 1027 | |
| | 1028 | /// Returns the nearest power of two less than or equal to value, or |
| | 1029 | /// zero if value is less than or equal to zero. |
| 992 | pub fn floorPowerOfTwo(comptime T: type, value: T) T { | 1030 | pub fn floorPowerOfTwo(comptime T: type, value: T) T { |
| 993 | var x = value; | 1031 | var x = value; |
| 994 | | 1032 | |
| ... | @@ -1042,6 +1080,9 @@ pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { | ... | @@ -1042,6 +1080,9 @@ pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { |
| 1042 | return @intCast(T, x); | 1080 | return @intCast(T, x); |
| 1043 | } | 1081 | } |
| 1044 | | 1082 | |
| | 1083 | /// Returns the next power of two (if the value is not already a power |
| | 1084 | /// of two). Only unsigned integers can be used. Zero is not an |
| | 1085 | /// allowed input. Asserts that the value fits. |
| 1045 | pub fn ceilPowerOfTwoAssert(comptime T: type, value: T) T { | 1086 | pub fn ceilPowerOfTwoAssert(comptime T: type, value: T) T { |
| 1046 | return ceilPowerOfTwo(T, value) catch unreachable; | 1087 | return ceilPowerOfTwo(T, value) catch unreachable; |
| 1047 | } | 1088 | } |
| ... | @@ -1080,6 +1121,8 @@ fn testCeilPowerOfTwo() !void { | ... | @@ -1080,6 +1121,8 @@ fn testCeilPowerOfTwo() !void { |
| 1080 | try testing.expectError(error.Overflow, ceilPowerOfTwo(u4, 9)); | 1121 | try testing.expectError(error.Overflow, ceilPowerOfTwo(u4, 9)); |
| 1081 | } | 1122 | } |
| 1082 | | 1123 | |
| | 1124 | /// Return the log base 2 of integer value x, rounding down to the |
| | 1125 | /// nearest integer. |
| 1083 | pub fn log2_int(comptime T: type, x: T) Log2Int(T) { | 1126 | pub fn log2_int(comptime T: type, x: T) Log2Int(T) { |
| 1084 | if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned) | 1127 | if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned) |
| 1085 | @compileError("log2_int requires an unsigned integer, found " ++ @typeName(T)); | 1128 | @compileError("log2_int requires an unsigned integer, found " ++ @typeName(T)); |
| ... | @@ -1087,6 +1130,8 @@ pub fn log2_int(comptime T: type, x: T) Log2Int(T) { | ... | @@ -1087,6 +1130,8 @@ pub fn log2_int(comptime T: type, x: T) Log2Int(T) { |
| 1087 | return @intCast(Log2Int(T), @typeInfo(T).Int.bits - 1 - @clz(T, x)); | 1130 | return @intCast(Log2Int(T), @typeInfo(T).Int.bits - 1 - @clz(T, x)); |
| 1088 | } | 1131 | } |
| 1089 | | 1132 | |
| | 1133 | /// Return the log base 2 of integer value x, rounding up to the |
| | 1134 | /// nearest integer. |
| 1090 | pub fn log2_int_ceil(comptime T: type, x: T) Log2IntCeil(T) { | 1135 | pub fn log2_int_ceil(comptime T: type, x: T) Log2IntCeil(T) { |
| 1091 | if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned) | 1136 | if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned) |
| 1092 | @compileError("log2_int_ceil requires an unsigned integer, found " ++ @typeName(T)); | 1137 | @compileError("log2_int_ceil requires an unsigned integer, found " ++ @typeName(T)); |
| ... | @@ -1109,8 +1154,9 @@ test "std.math.log2_int_ceil" { | ... | @@ -1109,8 +1154,9 @@ test "std.math.log2_int_ceil" { |
| 1109 | try testing.expect(log2_int_ceil(u32, 10) == 4); | 1154 | try testing.expect(log2_int_ceil(u32, 10) == 4); |
| 1110 | } | 1155 | } |
| 1111 | | 1156 | |
| 1112 | ///Cast a value to a different type. If the value doesn't fit in, or can't be perfectly represented by, | 1157 | /// Cast a value to a different type. If the value doesn't fit in, or |
| 1113 | ///the new type, it will be converted to the closest possible representation. | 1158 | /// can't be perfectly represented by, the new type, it will be |
| | 1159 | /// converted to the closest possible representation. |
| 1114 | pub fn lossyCast(comptime T: type, value: anytype) T { | 1160 | pub fn lossyCast(comptime T: type, value: anytype) T { |
| 1115 | switch (@typeInfo(T)) { | 1161 | switch (@typeInfo(T)) { |
| 1116 | .Float => { | 1162 | .Float => { |
| ... | @@ -1161,6 +1207,7 @@ test "math.f64_min" { | ... | @@ -1161,6 +1207,7 @@ test "math.f64_min" { |
| 1161 | try testing.expect(@bitCast(u64, fmin) == f64_min_u64); | 1207 | try testing.expect(@bitCast(u64, fmin) == f64_min_u64); |
| 1162 | } | 1208 | } |
| 1163 | | 1209 | |
| | 1210 | /// Returns the maximum value of integer type T. |
| 1164 | pub fn maxInt(comptime T: type) comptime_int { | 1211 | pub fn maxInt(comptime T: type) comptime_int { |
| 1165 | const info = @typeInfo(T); | 1212 | const info = @typeInfo(T); |
| 1166 | const bit_count = info.Int.bits; | 1213 | const bit_count = info.Int.bits; |
| ... | @@ -1168,6 +1215,7 @@ pub fn maxInt(comptime T: type) comptime_int { | ... | @@ -1168,6 +1215,7 @@ pub fn maxInt(comptime T: type) comptime_int { |
| 1168 | return (1 << (bit_count - @boolToInt(info.Int.signedness == .signed))) - 1; | 1215 | return (1 << (bit_count - @boolToInt(info.Int.signedness == .signed))) - 1; |
| 1169 | } | 1216 | } |
| 1170 | | 1217 | |
| | 1218 | /// Returns the minimum value of integer type T. |
| 1171 | pub fn minInt(comptime T: type) comptime_int { | 1219 | pub fn minInt(comptime T: type) comptime_int { |
| 1172 | const info = @typeInfo(T); | 1220 | const info = @typeInfo(T); |
| 1173 | const bit_count = info.Int.bits; | 1221 | const bit_count = info.Int.bits; |
| ... | @@ -1218,8 +1266,16 @@ test "max value type" { | ... | @@ -1218,8 +1266,16 @@ test "max value type" { |
| 1218 | try testing.expect(x == 2147483647); | 1266 | try testing.expect(x == 2147483647); |
| 1219 | } | 1267 | } |
| 1220 | | 1268 | |
| 1221 | pub fn mulWide(comptime T: type, a: T, b: T) std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits * 2) { | 1269 | /// Multiply a and b. Return type is wide enough to guarantee no |
| 1222 | const ResultInt = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits * 2); | 1270 | /// overflow. |
| | 1271 | pub fn mulWide(comptime T: type, a: T, b: T) std.meta.Int( |
| | 1272 | @typeInfo(T).Int.signedness, |
| | 1273 | @typeInfo(T).Int.bits * 2, |
| | 1274 | ) { |
| | 1275 | const ResultInt = std.meta.Int( |
| | 1276 | @typeInfo(T).Int.signedness, |
| | 1277 | @typeInfo(T).Int.bits * 2, |
| | 1278 | ); |
| 1223 | return @as(ResultInt, a) * @as(ResultInt, b); | 1279 | return @as(ResultInt, a) * @as(ResultInt, b); |
| 1224 | } | 1280 | } |
| 1225 | | 1281 | |