Function wrap [src]

Odd sawtooth function | / | / / / |/ / --/----/----/-- / /| / / / | / | Limit x to the half-open interval [-r, r).

Prototype

pub fn wrap(x: anytype, r: anytype) @TypeOf(x)

Example

test wrap { // Within range try testing.expect(wrap(@as(i32, -75), @as(i32, 180)) == -75); try testing.expect(wrap(@as(i32, -75), @as(i32, -180)) == -75); // Below try testing.expect(wrap(@as(i32, -225), @as(i32, 180)) == 135); try testing.expect(wrap(@as(i32, -225), @as(i32, -180)) == 135); // Above try testing.expect(wrap(@as(i32, 361), @as(i32, 180)) == 1); try testing.expect(wrap(@as(i32, 361), @as(i32, -180)) == 1); // One period, right limit, positive r try testing.expect(wrap(@as(i32, 180), @as(i32, 180)) == -180); // One period, left limit, positive r try testing.expect(wrap(@as(i32, -180), @as(i32, 180)) == -180); // One period, right limit, negative r try testing.expect(wrap(@as(i32, 180), @as(i32, -180)) == 180); // One period, left limit, negative r try testing.expect(wrap(@as(i32, -180), @as(i32, -180)) == 180); // Two periods, right limit, positive r try testing.expect(wrap(@as(i32, 540), @as(i32, 180)) == -180); // Two periods, left limit, positive r try testing.expect(wrap(@as(i32, -540), @as(i32, 180)) == -180); // Two periods, right limit, negative r try testing.expect(wrap(@as(i32, 540), @as(i32, -180)) == 180); // Two periods, left limit, negative r try testing.expect(wrap(@as(i32, -540), @as(i32, -180)) == 180); // Floating point try testing.expect(wrap(@as(f32, 1.125), @as(f32, 1.0)) == -0.875); try testing.expect(wrap(@as(f32, -127.5), @as(f32, 180)) == -127.5); // Mix of comptime and non-comptime var i: i32 = 1; _ = &i; try testing.expect(wrap(i, 10) == 1); const limit: i32 = 180; // Within range try testing.expect(wrap(@as(i32, -75), limit) == -75); // Below try testing.expect(wrap(@as(i32, -225), limit) == 135); // Above try testing.expect(wrap(@as(i32, 361), limit) == 1); }

Source

pub fn wrap(x: anytype, r: anytype) @TypeOf(x) { const info_x = @typeInfo(@TypeOf(x)); const info_r = @typeInfo(@TypeOf(r)); if (info_x == .int and info_x.int.signedness != .signed) { @compileError("x must be floating point, comptime integer, or signed integer."); } switch (info_r) { .int => { // in the rare usecase of r not being comptime_int or float, // take the penalty of having an intermediary type conversion, // otherwise the alternative is to unwind iteratively to avoid overflow const R = comptime do: { var info = info_r; info.int.bits += 1; info.int.signedness = .signed; break :do @Type(info); }; const radius: if (info_r.int.signedness == .signed) @TypeOf(r) else R = r; return @intCast(@mod(x - radius, 2 * @as(R, r)) - r); // provably impossible to overflow }, else => { return @mod(x - r, 2 * r) - r; }, } }