| author | |
| committer | |
| log | 05915b85dd3c00c40bf6645e0f09157be04dc829 |
| tree | eadc479bc345db45d66f16f888a217bc68f2b041 |
| parent | eac1e613be56875a08102bd06e333a0621600ee6 |
These are the standard complex multiplication/division functions
required by the C standard (Annex G).
Don't get me started on the standard's handling of complex-infinity...16 files changed, 439 insertions(+), 1 deletions(-)
lib/compiler_rt.zig+15-1| ... | @@ -15,11 +15,25 @@ comptime { | ... | @@ -15,11 +15,25 @@ comptime { |
| 15 | _ = @import("compiler_rt/subxf3.zig"); | 15 | _ = @import("compiler_rt/subxf3.zig"); |
| 16 | 16 | ||
| 17 | _ = @import("compiler_rt/mulf3.zig"); | 17 | _ = @import("compiler_rt/mulf3.zig"); |
| 18 | _ = @import("compiler_rt/muldf3.zig"); | ||
| 19 | _ = @import("compiler_rt/mulsf3.zig"); | 18 | _ = @import("compiler_rt/mulsf3.zig"); |
| 19 | _ = @import("compiler_rt/muldf3.zig"); | ||
| 20 | _ = @import("compiler_rt/multf3.zig"); | 20 | _ = @import("compiler_rt/multf3.zig"); |
| 21 | _ = @import("compiler_rt/mulxf3.zig"); | 21 | _ = @import("compiler_rt/mulxf3.zig"); |
| 22 | 22 | ||
| 23 | _ = @import("compiler_rt/mulc3.zig"); | ||
| 24 | _ = @import("compiler_rt/mulhc3.zig"); | ||
| 25 | _ = @import("compiler_rt/mulsc3.zig"); | ||
| 26 | _ = @import("compiler_rt/muldc3.zig"); | ||
| 27 | _ = @import("compiler_rt/mulxc3.zig"); | ||
| 28 | _ = @import("compiler_rt/multc3.zig"); | ||
| 29 | |||
| 30 | _ = @import("compiler_rt/divc3.zig"); | ||
| 31 | _ = @import("compiler_rt/divhc3.zig"); | ||
| 32 | _ = @import("compiler_rt/divsc3.zig"); | ||
| 33 | _ = @import("compiler_rt/divdc3.zig"); | ||
| 34 | _ = @import("compiler_rt/divxc3.zig"); | ||
| 35 | _ = @import("compiler_rt/divtc3.zig"); | ||
| 36 | |||
| 23 | _ = @import("compiler_rt/negsf2.zig"); | 37 | _ = @import("compiler_rt/negsf2.zig"); |
| 24 | _ = @import("compiler_rt/negdf2.zig"); | 38 | _ = @import("compiler_rt/negdf2.zig"); |
| 25 | _ = @import("compiler_rt/negtf2.zig"); | 39 | _ = @import("compiler_rt/negtf2.zig"); |
lib/compiler_rt/divc3.zig created+62| ... | @@ -0,0 +1,62 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const isNan = std.math.isNan; | ||
| 3 | const isInf = std.math.isInf; | ||
| 4 | const scalbn = std.math.scalbn; | ||
| 5 | const ilogb = std.math.ilogb; | ||
| 6 | const max = std.math.max; | ||
| 7 | const fabs = std.math.fabs; | ||
| 8 | const maxInt = std.math.maxInt; | ||
| 9 | const minInt = std.math.minInt; | ||
| 10 | const isFinite = std.math.isFinite; | ||
| 11 | const copysign = std.math.copysign; | ||
| 12 | const Complex = @import("mulc3.zig").Complex; | ||
| 13 | |||
| 14 | /// Implementation based on Annex G of C17 Standard (N2176) | ||
| 15 | pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { | ||
| 16 | var c = c_in; | ||
| 17 | var d = d_in; | ||
| 18 | |||
| 19 | // logbw used to prevent under/over-flow | ||
| 20 | const logbw = ilogb(max(fabs(c), fabs(d))); | ||
| 21 | const logbw_finite = logbw != maxInt(i32) and logbw != minInt(i32); | ||
| 22 | const ilogbw = if (logbw_finite) b: { | ||
| 23 | c = scalbn(c, -logbw); | ||
| 24 | d = scalbn(d, -logbw); | ||
| 25 | break :b logbw; | ||
| 26 | } else 0; | ||
| 27 | const denom = c * c + d * d; | ||
| 28 | const result = Complex(T){ | ||
| 29 | .real = scalbn((a * c + b * d) / denom, -ilogbw), | ||
| 30 | .imag = scalbn((b * c - a * d) / denom, -ilogbw), | ||
| 31 | }; | ||
| 32 | |||
| 33 | // Recover infinities and zeros that computed as NaN+iNaN; | ||
| 34 | // the only cases are non-zero/zero, infinite/finite, and finite/infinite, ... | ||
| 35 | if (isNan(result.real) and isNan(result.imag)) { | ||
| 36 | const zero: T = 0.0; | ||
| 37 | const one: T = 1.0; | ||
| 38 | |||
| 39 | if ((denom == 0.0) and (!isNan(a) or !isNan(b))) { | ||
| 40 | return .{ | ||
| 41 | .real = copysign(std.math.inf(T), c) * a, | ||
| 42 | .imag = copysign(std.math.inf(T), c) * b, | ||
| 43 | }; | ||
| 44 | } else if ((isInf(a) or isInf(b)) and isFinite(c) and isFinite(d)) { | ||
| 45 | const boxed_a = copysign(if (isInf(a)) one else zero, a); | ||
| 46 | const boxed_b = copysign(if (isInf(b)) one else zero, b); | ||
| 47 | return .{ | ||
| 48 | .real = std.math.inf(T) * (boxed_a * c - boxed_b * d), | ||
| 49 | .imag = std.math.inf(T) * (boxed_b * c - boxed_a * d), | ||
| 50 | }; | ||
| 51 | } else if (logbw == maxInt(i32) and isFinite(a) and isFinite(b)) { | ||
| 52 | const boxed_c = copysign(if (isInf(c)) one else zero, c); | ||
| 53 | const boxed_d = copysign(if (isInf(d)) one else zero, d); | ||
| 54 | return .{ | ||
| 55 | .real = 0.0 * (a * boxed_c + b * boxed_d), | ||
| 56 | .imag = 0.0 * (b * boxed_c - a * boxed_d), | ||
| 57 | }; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | return result; | ||
| 62 | } | ||
lib/compiler_rt/divc3_test.zig created+77| ... | @@ -0,0 +1,77 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | const Complex = @import("./mulc3.zig").Complex; | ||
| 6 | const __divhc3 = @import("./divhc3.zig").__divhc3; | ||
| 7 | const __divsc3 = @import("./divsc3.zig").__divsc3; | ||
| 8 | const __divdc3 = @import("./divdc3.zig").__divdc3; | ||
| 9 | const __divxc3 = @import("./divxc3.zig").__divxc3; | ||
| 10 | const __divtc3 = @import("./divtc3.zig").__divtc3; | ||
| 11 | |||
| 12 | test { | ||
| 13 | try testDiv(f16, __divhc3); | ||
| 14 | try testDiv(f32, __divsc3); | ||
| 15 | try testDiv(f64, __divdc3); | ||
| 16 | try testDiv(f80, __divxc3); | ||
| 17 | try testDiv(f128, __divtc3); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn testDiv(comptime T: type, comptime f: fn (T, T, T, T) callconv(.C) Complex(T)) !void { | ||
| 21 | { | ||
| 22 | var a: T = 1.0; | ||
| 23 | var b: T = 0.0; | ||
| 24 | var c: T = -1.0; | ||
| 25 | var d: T = 0.0; | ||
| 26 | |||
| 27 | const result = f(a, b, c, d); | ||
| 28 | try expect(result.real == -1.0); | ||
| 29 | try expect(result.imag == 0.0); | ||
| 30 | } | ||
| 31 | { | ||
| 32 | var a: T = 1.0; | ||
| 33 | var b: T = 0.0; | ||
| 34 | var c: T = -4.0; | ||
| 35 | var d: T = 0.0; | ||
| 36 | |||
| 37 | const result = f(a, b, c, d); | ||
| 38 | try expect(result.real == -0.25); | ||
| 39 | try expect(result.imag == 0.0); | ||
| 40 | } | ||
| 41 | { | ||
| 42 | // if the first operand is an infinity and the second operand is a finite number, then the | ||
| 43 | // result of the / operator is an infinity; | ||
| 44 | var a: T = -math.inf(T); | ||
| 45 | var b: T = 0.0; | ||
| 46 | var c: T = -4.0; | ||
| 47 | var d: T = 1.0; | ||
| 48 | |||
| 49 | const result = f(a, b, c, d); | ||
| 50 | try expect(result.real == math.inf(T)); | ||
| 51 | try expect(result.imag == math.inf(T)); | ||
| 52 | } | ||
| 53 | { | ||
| 54 | // if the first operand is a finite number and the second operand is an infinity, then the | ||
| 55 | // result of the / operator is a zero; | ||
| 56 | var a: T = 17.2; | ||
| 57 | var b: T = 0.0; | ||
| 58 | var c: T = -math.inf(T); | ||
| 59 | var d: T = 0.0; | ||
| 60 | |||
| 61 | const result = f(a, b, c, d); | ||
| 62 | try expect(result.real == -0.0); | ||
| 63 | try expect(result.imag == 0.0); | ||
| 64 | } | ||
| 65 | { | ||
| 66 | // if the first operand is a nonzero finite number or an infinity and the second operand is | ||
| 67 | // a zero, then the result of the / operator is an infinity | ||
| 68 | var a: T = 1.1; | ||
| 69 | var b: T = 0.1; | ||
| 70 | var c: T = 0.0; | ||
| 71 | var d: T = 0.0; | ||
| 72 | |||
| 73 | const result = f(a, b, c, d); | ||
| 74 | try expect(result.real == math.inf(T)); | ||
| 75 | try expect(result.imag == math.inf(T)); | ||
| 76 | } | ||
| 77 | } | ||
lib/compiler_rt/divdc3.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const divc3 = @import("./divc3.zig"); | ||
| 3 | const Complex = @import("./mulc3.zig").Complex; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(__divdc3, .{ .name = "__divdc3", .linkage = common.linkage }); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub fn __divdc3(a: f64, b: f64, c: f64, d: f64) callconv(.C) Complex(f64) { | ||
| 10 | return divc3.divc3(f64, a, b, c, d); | ||
| 11 | } | ||
lib/compiler_rt/divhc3.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const divc3 = @import("./divc3.zig"); | ||
| 3 | const Complex = @import("./mulc3.zig").Complex; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(__divhc3, .{ .name = "__divhc3", .linkage = common.linkage }); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub fn __divhc3(a: f16, b: f16, c: f16, d: f16) callconv(.C) Complex(f16) { | ||
| 10 | return divc3.divc3(f16, a, b, c, d); | ||
| 11 | } | ||
lib/compiler_rt/divsc3.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const divc3 = @import("./divc3.zig"); | ||
| 3 | const Complex = @import("./mulc3.zig").Complex; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(__divsc3, .{ .name = "__divsc3", .linkage = common.linkage }); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub fn __divsc3(a: f32, b: f32, c: f32, d: f32) callconv(.C) Complex(f32) { | ||
| 10 | return divc3.divc3(f32, a, b, c, d); | ||
| 11 | } | ||
lib/compiler_rt/divtc3.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const divc3 = @import("./divc3.zig"); | ||
| 3 | const Complex = @import("./mulc3.zig").Complex; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(__divtc3, .{ .name = "__divtc3", .linkage = common.linkage }); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub fn __divtc3(a: f128, b: f128, c: f128, d: f128) callconv(.C) Complex(f128) { | ||
| 10 | return divc3.divc3(f128, a, b, c, d); | ||
| 11 | } | ||
lib/compiler_rt/divxc3.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const divc3 = @import("./divc3.zig"); | ||
| 3 | const Complex = @import("./mulc3.zig").Complex; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(__divxc3, .{ .name = "__divxc3", .linkage = common.linkage }); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub fn __divxc3(a: f80, b: f80, c: f80, d: f80) callconv(.C) Complex(f80) { | ||
| 10 | return divc3.divc3(f80, a, b, c, d); | ||
| 11 | } | ||
lib/compiler_rt/mulc3.zig created+79| ... | @@ -0,0 +1,79 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const isNan = std.math.isNan; | ||
| 3 | const isInf = std.math.isInf; | ||
| 4 | const copysign = std.math.copysign; | ||
| 5 | |||
| 6 | pub fn Complex(comptime T: type) type { | ||
| 7 | return extern struct { | ||
| 8 | real: T, | ||
| 9 | imag: T, | ||
| 10 | }; | ||
| 11 | } | ||
| 12 | |||
| 13 | /// Implementation based on Annex G of C17 Standard (N2176) | ||
| 14 | pub inline fn mulc3(comptime T: type, a_in: T, b_in: T, c_in: T, d_in: T) Complex(T) { | ||
| 15 | var a = a_in; | ||
| 16 | var b = b_in; | ||
| 17 | var c = c_in; | ||
| 18 | var d = d_in; | ||
| 19 | |||
| 20 | const ac = a * c; | ||
| 21 | const bd = b * d; | ||
| 22 | const ad = a * d; | ||
| 23 | const bc = b * c; | ||
| 24 | |||
| 25 | const zero: T = 0.0; | ||
| 26 | const one: T = 1.0; | ||
| 27 | |||
| 28 | var z = Complex(T){ | ||
| 29 | .real = ac - bd, | ||
| 30 | .imag = ad + bc, | ||
| 31 | }; | ||
| 32 | if (isNan(z.real) and isNan(z.imag)) { | ||
| 33 | var recalc: bool = false; | ||
| 34 | |||
| 35 | if (isInf(a) or isInf(b)) { // (a + ib) is infinite | ||
| 36 | |||
| 37 | // "Box" the infinity (+/-inf goes to +/-1, all finite values go to 0) | ||
| 38 | a = copysign(if (isInf(a)) one else zero, a); | ||
| 39 | b = copysign(if (isInf(b)) one else zero, b); | ||
| 40 | |||
| 41 | // Replace NaNs in the other factor with (signed) 0 | ||
| 42 | if (isNan(c)) c = copysign(zero, c); | ||
| 43 | if (isNan(d)) d = copysign(zero, d); | ||
| 44 | |||
| 45 | recalc = true; | ||
| 46 | } | ||
| 47 | |||
| 48 | if (isInf(c) or isInf(d)) { // (c + id) is infinite | ||
| 49 | |||
| 50 | // "Box" the infinity (+/-inf goes to +/-1, all finite values go to 0) | ||
| 51 | c = copysign(if (isInf(c)) one else zero, c); | ||
| 52 | d = copysign(if (isInf(d)) one else zero, d); | ||
| 53 | |||
| 54 | // Replace NaNs in the other factor with (signed) 0 | ||
| 55 | if (isNan(a)) a = copysign(zero, a); | ||
| 56 | if (isNan(b)) b = copysign(zero, b); | ||
| 57 | |||
| 58 | recalc = true; | ||
| 59 | } | ||
| 60 | |||
| 61 | if (!recalc and (isInf(ac) or isInf(bd) or isInf(ad) or isInf(bc))) { | ||
| 62 | |||
| 63 | // Recover infinities from overflow by changing NaNs to 0 | ||
| 64 | if (isNan(a)) a = copysign(zero, a); | ||
| 65 | if (isNan(b)) b = copysign(zero, b); | ||
| 66 | if (isNan(c)) c = copysign(zero, c); | ||
| 67 | if (isNan(d)) d = copysign(zero, d); | ||
| 68 | |||
| 69 | recalc = true; | ||
| 70 | } | ||
| 71 | if (recalc) { | ||
| 72 | return .{ | ||
| 73 | .real = std.math.inf(T) * (a * c - b * d), | ||
| 74 | .imag = std.math.inf(T) * (a * d + b * c), | ||
| 75 | }; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | return z; | ||
| 79 | } | ||
lib/compiler_rt/mulc3_test.zig created+65| ... | @@ -0,0 +1,65 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | const Complex = @import("./mulc3.zig").Complex; | ||
| 6 | const __mulhc3 = @import("./mulhc3.zig").__mulhc3; | ||
| 7 | const __mulsc3 = @import("./mulsc3.zig").__mulsc3; | ||
| 8 | const __muldc3 = @import("./muldc3.zig").__muldc3; | ||
| 9 | const __mulxc3 = @import("./mulxc3.zig").__mulxc3; | ||
| 10 | const __multc3 = @import("./multc3.zig").__multc3; | ||
| 11 | |||
| 12 | test { | ||
| 13 | try testMul(f16, __mulhc3); | ||
| 14 | try testMul(f32, __mulsc3); | ||
| 15 | try testMul(f64, __muldc3); | ||
| 16 | try testMul(f80, __mulxc3); | ||
| 17 | try testMul(f128, __multc3); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn testMul(comptime T: type, comptime f: fn (T, T, T, T) callconv(.C) Complex(T)) !void { | ||
| 21 | { | ||
| 22 | var a: T = 1.0; | ||
| 23 | var b: T = 0.0; | ||
| 24 | var c: T = -1.0; | ||
| 25 | var d: T = 0.0; | ||
| 26 | |||
| 27 | const result = f(a, b, c, d); | ||
| 28 | try expect(result.real == -1.0); | ||
| 29 | try expect(result.imag == 0.0); | ||
| 30 | } | ||
| 31 | { | ||
| 32 | var a: T = 1.0; | ||
| 33 | var b: T = 0.0; | ||
| 34 | var c: T = -4.0; | ||
| 35 | var d: T = 0.0; | ||
| 36 | |||
| 37 | const result = f(a, b, c, d); | ||
| 38 | try expect(result.real == -4.0); | ||
| 39 | try expect(result.imag == 0.0); | ||
| 40 | } | ||
| 41 | { | ||
| 42 | // if one operand is an infinity and the other operand is a nonzero finite number or an infinity, | ||
| 43 | // then the result of the * operator is an infinity; | ||
| 44 | var a: T = math.inf(T); | ||
| 45 | var b: T = -math.inf(T); | ||
| 46 | var c: T = 1.0; | ||
| 47 | var d: T = 0.0; | ||
| 48 | |||
| 49 | const result = f(a, b, c, d); | ||
| 50 | try expect(result.real == math.inf(T)); | ||
| 51 | try expect(result.imag == -math.inf(T)); | ||
| 52 | } | ||
| 53 | { | ||
| 54 | // if one operand is an infinity and the other operand is a nonzero finite number or an infinity, | ||
| 55 | // then the result of the * operator is an infinity; | ||
| 56 | var a: T = math.inf(T); | ||
| 57 | var b: T = -1.0; | ||
| 58 | var c: T = 1.0; | ||
| 59 | var d: T = math.inf(T); | ||
| 60 | |||
| 61 | const result = f(a, b, c, d); | ||
| 62 | try expect(result.real == math.inf(T)); | ||
| 63 | try expect(result.imag == math.inf(T)); | ||
| 64 | } | ||
| 65 | } | ||
lib/compiler_rt/muldc3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulc3 = @import("./mulc3.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__muldc3, .{ .name = "__muldc3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __muldc3(a: f64, b: f64, c: f64, d: f64) callconv(.C) mulc3.Complex(f64) { | ||
| 11 | return mulc3.mulc3(f64, a, b, c, d); | ||
| 12 | } | ||
lib/compiler_rt/mulhc3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulc3 = @import("./mulc3.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__mulhc3, .{ .name = "__mulhc3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __mulhc3(a: f16, b: f16, c: f16, d: f16) callconv(.C) mulc3.Complex(f16) { | ||
| 11 | return mulc3.mulc3(f16, a, b, c, d); | ||
| 12 | } | ||
lib/compiler_rt/mulsc3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulc3 = @import("./mulc3.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__mulsc3, .{ .name = "__mulsc3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __mulsc3(a: f32, b: f32, c: f32, d: f32) callconv(.C) mulc3.Complex(f32) { | ||
| 11 | return mulc3.mulc3(f32, a, b, c, d); | ||
| 12 | } | ||
lib/compiler_rt/multc3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulc3 = @import("./mulc3.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__multc3, .{ .name = "__multc3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __multc3(a: f128, b: f128, c: f128, d: f128) callconv(.C) mulc3.Complex(f128) { | ||
| 11 | return mulc3.mulc3(f128, a, b, c, d); | ||
| 12 | } | ||
lib/compiler_rt/mulxc3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulc3 = @import("./mulc3.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__mulxc3, .{ .name = "__mulxc3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __mulxc3(a: f80, b: f80, c: f80, d: f80) callconv(.C) mulc3.Complex(f80) { | ||
| 11 | return mulc3.mulc3(f80, a, b, c, d); | ||
| 12 | } | ||
test/standalone/c_compiler/test.c+26| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | #include <assert.h> | 1 | #include <assert.h> |
| 2 | #include <complex.h> | ||
| 2 | #include <stdio.h> | 3 | #include <stdio.h> |
| 3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
| 4 | 5 | ||
| ... | @@ -24,5 +25,30 @@ int main (int argc, char *argv[]) | ... | @@ -24,5 +25,30 @@ int main (int argc, char *argv[]) |
| 24 | 25 | ||
| 25 | if (!ok) abort(); | 26 | if (!ok) abort(); |
| 26 | 27 | ||
| 28 | // Test some basic arithmetic from compiler-rt | ||
| 29 | { | ||
| 30 | double complex z = 0.0 + I * 4.0; | ||
| 31 | double complex w = 0.0 + I * 16.0; | ||
| 32 | double complex product = z * w; | ||
| 33 | double complex quotient = z / w; | ||
| 34 | |||
| 35 | if (!(creal(product) == -64.0)) abort(); | ||
| 36 | if (!(cimag(product) == 0.0)) abort(); | ||
| 37 | if (!(creal(quotient) == 0.25)) abort(); | ||
| 38 | if (!(cimag(quotient) == 0.0)) abort(); | ||
| 39 | } | ||
| 40 | |||
| 41 | { | ||
| 42 | float complex z = 4.0 + I * 4.0; | ||
| 43 | float complex w = 2.0 - I * 2.0; | ||
| 44 | float complex product = z * w; | ||
| 45 | float complex quotient = z / w; | ||
| 46 | |||
| 47 | if (!(creal(product) == 16.0)) abort(); | ||
| 48 | if (!(cimag(product) == 0.0)) abort(); | ||
| 49 | if (!(creal(quotient) == 0.0)) abort(); | ||
| 50 | if (!(cimag(quotient) == 2.0)) abort(); | ||
| 51 | } | ||
| 52 | |||
| 27 | return EXIT_SUCCESS; | 53 | return EXIT_SUCCESS; |
| 28 | } | 54 | } |