authorgravatar for nathan@nmichaels.orgNathan Michaels <nathan@nmichaels.org> 2021-09-30 00:10:25-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-02 16:06:03-04:00
log4916e26be434309209585a7c8a7918ed58c79466
treeefbb41dd160bd766131a932fa133dd0f97a670d4
parent468ed7ada50c743eabe01b36d0ee9f090d80e00a

Document some functions in std.math.


1 files changed, 72 insertions(+), 16 deletions(-)

lib/std/math.zig+72-16
...@@ -277,6 +277,8 @@ test {...@@ -277,6 +277,8 @@ test {
277 std.testing.refAllDecls(@This());277 std.testing.refAllDecls(@This());
278}278}
279279
280/// Returns the number of bits in the mantissa of floating point type
281/// T.
280pub fn floatMantissaBits(comptime T: type) comptime_int {282pub fn floatMantissaBits(comptime T: type) comptime_int {
281 assert(@typeInfo(T) == .Float);283 assert(@typeInfo(T) == .Float);
282284
...@@ -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}
292294
295/// Returns the number of bits in the exponent of floating point type
296/// T.
293pub fn floatExponentBits(comptime T: type) comptime_int {297pub fn floatExponentBits(comptime T: type) comptime_int {
294 assert(@typeInfo(T) == .Float);298 assert(@typeInfo(T) == .Float);
295299
...@@ -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}
324328
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.
327pub fn min(x: anytype, y: anytype) Min(@TypeOf(x), @TypeOf(y)) {331pub 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 this334 // 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 this342 // 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}
377383
378/// Finds the min of three numbers384/// Finds the minimum of three numbers.
379pub fn min3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) {385pub 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}
391397
398/// Returns the maximum of two numbers. Return type is the one with the
399/// larger range.
392pub fn max(x: anytype, y: anytype) @TypeOf(x, y) {400pub 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}
400408
401/// Finds the max of three numbers409/// Finds the maximum of three numbers.
402pub fn max3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) {410pub 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}
414422
423/// Limit val to the inclusive range [lower, upper].
415pub fn clamp(val: anytype, lower: anytype, upper: anytype) @TypeOf(val, lower, upper) {424pub 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}
435444
445/// Returns the product of a and b. Returns an error on overflow.
436pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {446pub 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}
440450
451/// Returns the sum of a and b. Returns an error on overflow.
441pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {452pub 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}
446457
458/// Returns a - b, or an error on overflow.
447pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {459pub 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}
455467
468/// Shifts a left by shift_amt. Returns an error on overflow. shift_amt
469/// is unsigned.
456pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {470pub 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}
540554
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.
543pub fn rotr(comptime T: type, x: T, r: anytype) T {557pub 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}
568582
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.
571pub fn rotl(comptime T: type, x: T, r: anytype) T {585pub 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}
596610
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.
597pub fn Log2Int(comptime T: type) type {613pub fn Log2Int(comptime T: type) type {
598 // comptime ceil log2614 // 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}
607623
624/// Returns an unsigned int type that can hold the number of bits in T.
608pub fn Log2IntCeil(comptime T: type) type {625pub fn Log2IntCeil(comptime T: type) type {
609 // comptime ceil log2626 // 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}
618635
636/// Returns the smallest integer type that can hold both from and to.
619pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {637pub 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}
693711
712/// Returns the absolute value of x, where x is a value of an integer
713/// type.
694pub fn absInt(x: anytype) !@TypeOf(x) {714pub 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 absInt716 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}
726746
747/// Divide numerator by denominator, rounding toward zero. Returns an
748/// error on overflow or when denominator is zero.
727pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {749pub 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}
747769
770/// Divide numerator by denominator, rounding toward negative
771/// infinity. Returns an error on overflow or when denominator is
772/// zero.
748pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {773pub 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}
768793
794/// Divide numerator by denominator, rounding toward positive
795/// infinity. Returns an error on overflow or when denominator is
796/// zero.
769pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T {797pub 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}
821849
850/// Divide numerator by denominator. Return an error if quotient is
851/// not an integer, denominator is zero, or on overflow.
822pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {852pub 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}
846876
877/// Returns numerator modulo denominator, or an error if denominator is
878/// zero or negative. Negative numerators never result in negative
879/// return values.
847pub fn mod(comptime T: type, numerator: T, denominator: T) !T {880pub 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}
869902
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.
870pub fn rem(comptime T: type, numerator: T, denominator: T) !T {906pub 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}
9911027
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.
992pub fn floorPowerOfTwo(comptime T: type, value: T) T {1030pub fn floorPowerOfTwo(comptime T: type, value: T) T {
993 var x = value;1031 var x = value;
9941032
...@@ -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}
10441082
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.
1045pub fn ceilPowerOfTwoAssert(comptime T: type, value: T) T {1086pub 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}
10821123
1124/// Return the log base 2 of integer value x, rounding down to the
1125/// nearest integer.
1083pub fn log2_int(comptime T: type, x: T) Log2Int(T) {1126pub 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}
10891132
1133/// Return the log base 2 of integer value x, rounding up to the
1134/// nearest integer.
1090pub fn log2_int_ceil(comptime T: type, x: T) Log2IntCeil(T) {1135pub 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}
11111156
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.
1114pub fn lossyCast(comptime T: type, value: anytype) T {1160pub 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}
11631209
1210/// Returns the maximum value of integer type T.
1164pub fn maxInt(comptime T: type) comptime_int {1211pub 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}
11701217
1218/// Returns the minimum value of integer type T.
1171pub fn minInt(comptime T: type) comptime_int {1219pub 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}
12201268
1221pub 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.
1271pub 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}
12251281