@@ -1125,3 +1125,190 @@ function complex(A::AbstractArray{T}) where T
11251125 end
11261126 convert (AbstractArray{typeof (complex (zero (T)))}, A)
11271127end
1128+
1129+ const ComplexFloat = Complex{<: AbstractFloat }
1130+
1131+ # # Multi-word floating-point for `Complex`
1132+
1133+ complex_twiceprec (real:: Tw , imag:: Tw ) where {Tw<: TwicePrecision{<:AbstractFloat} } =
1134+ TwicePrecision (
1135+ complex (real. hi, imag. hi),
1136+ complex (real. lo, imag. lo),
1137+ )
1138+
1139+ real (c:: TwicePrecision{<:ComplexFloat} ) =
1140+ TwicePrecision (real (c. hi), real (c. lo))
1141+
1142+ imag (c:: TwicePrecision{<:ComplexFloat} ) =
1143+ TwicePrecision (imag (c. hi), imag (c. lo))
1144+
1145+ # +
1146+
1147+ function + (x:: TwicePrecision{<:AbstractFloat} , y:: ComplexFloat )
1148+ y_re = real (y)
1149+ y_im = imag (y)
1150+ sum = x + y_re
1151+ TwicePrecision (complex (sum. hi, y_im), complex (sum. lo))
1152+ end
1153+
1154+ function + (
1155+ x:: TwicePrecision{<:ComplexFloat} ,
1156+ y:: Union{AbstractFloat,TwicePrecision{<:AbstractFloat}} ,
1157+ )
1158+ x_re = real (x)
1159+ x_im = imag (x)
1160+ sum = x_re + y
1161+ complex_twiceprec (sum, x_im)
1162+ end
1163+
1164+ + (x:: TwicePrecision{T} , y:: T ) where {T<: ComplexFloat } =
1165+ TwicePrecision (mw_operate (+ , Tuple (x), (y,))... )
1166+
1167+ + (x:: TwicePrecision{<:AbstractFloat} , y:: TwicePrecision{<:ComplexFloat} ) =
1168+ y + x
1169+
1170+ + (x:: Tw , y:: Tw ) where {Tw<: TwicePrecision{<:ComplexFloat} } =
1171+ TwicePrecision (mw_operate (+ , Tuple (x), Tuple (y))... )
1172+
1173+ # -
1174+
1175+ - (x:: TwicePrecision{<:AbstractFloat} , y:: ComplexFloat ) =
1176+ x + - y
1177+
1178+ - (x:: TwicePrecision{<:ComplexFloat} , y:: Union{AbstractFloat,ComplexFloat} ) =
1179+ x + - y
1180+
1181+ - (
1182+ x:: TwicePrecision{<:ComplexFloat} ,
1183+ y:: TwicePrecision{<:Union{AbstractFloat,ComplexFloat}} ,
1184+ ) =
1185+ x + - y
1186+
1187+ - (x:: TwicePrecision{<:ComplexFloat} , y:: TwicePrecision{<:AbstractFloat} ) =
1188+ x + - y
1189+
1190+ # *
1191+
1192+ function * (x:: TwicePrecision{<:AbstractFloat} , y:: ComplexFloat )
1193+ y_re = real (y)
1194+ y_im = imag (y)
1195+ res_re = x * y_re
1196+ res_im = x * y_im
1197+ complex_twiceprec (res_re, res_im)
1198+ end
1199+
1200+ function * (
1201+ x:: TwicePrecision{<:ComplexFloat} ,
1202+ y:: Union{AbstractFloat,TwicePrecision{<:AbstractFloat}} ,
1203+ )
1204+ x_re = real (x)
1205+ x_im = imag (x)
1206+ res_re = x_re * y
1207+ res_im = x_im * y
1208+ complex_twiceprec (res_re, res_im)
1209+ end
1210+
1211+ function * (x:: Tw , y:: Union{T,Tw} ) where {T<: ComplexFloat ,Tw<: TwicePrecision{T} }
1212+ # TODO : evaluate whether it makes sense to write custom code, with
1213+ # separate methods for `*(x::Tw, y::T)` and `*(x::Tw, y::Tw)`.
1214+
1215+ # TODO : try preventing some overflows and underflows?
1216+
1217+ # TODO : for `*(x::Tw, y::T)`: evaluate whether it makes sense to
1218+ # use Algorithm 3 from the paper "Accurate Complex Multiplication
1219+ # in Floating-Point Arithmetic", https://hal.science/hal-02001080v2
1220+ # The algorithm must first be adapted to return double-word results
1221+ # as explained in the same paper.
1222+
1223+ x_re = real (x)
1224+ x_im = imag (x)
1225+ y_re = real (y)
1226+ y_im = imag (y)
1227+ res_re = x_re* y_re - x_im* y_im
1228+ res_im = x_im* y_re + x_re* y_im
1229+ complex_twiceprec (res_re, res_im)
1230+ end
1231+
1232+ * (x:: TwicePrecision{<:AbstractFloat} , y:: TwicePrecision{<:ComplexFloat} ) =
1233+ y * x
1234+
1235+ # abs2
1236+
1237+ function abs2 (x:: TwicePrecision{<:ComplexFloat} )
1238+ # TODO : evaluate whether it makes sense to write custom code
1239+
1240+ # TODO : try preventing some overflows and underflows?
1241+
1242+ re = real (x)
1243+ im = imag (x)
1244+ re* re + im* im
1245+ end
1246+
1247+ # /
1248+
1249+ function div_complex_twiceprec_impl (
1250+ x:: Union{AbstractFloat,TwicePrecision{<:AbstractFloat}} ,
1251+ y,
1252+ )
1253+ # TODO : use the inverse of abs2 instead for better performance?
1254+ a = abs2 (y)
1255+
1256+ y_re = real (y)
1257+ y_im = imag (y)
1258+ res_re = x* y_re/ a
1259+ res_im = - x* y_im/ a
1260+ complex_twiceprec (res_re, res_im)
1261+ end
1262+
1263+ function div_complex_twiceprec_impl (
1264+ x:: Union{ComplexFloat,TwicePrecision{<:ComplexFloat}} ,
1265+ y,
1266+ )
1267+ # TODO : use the inverse of abs2 instead for better performance?
1268+ a = abs2 (y)
1269+
1270+ x_re = real (x)
1271+ x_im = imag (x)
1272+ y_re = real (y)
1273+ y_im = imag (y)
1274+ res_re = (x_re* y_re + x_im* y_im) / a
1275+ res_im = (x_im* y_re - x_re* y_im) / a
1276+ complex_twiceprec (res_re, res_im)
1277+ end
1278+
1279+ / (
1280+ x:: TwicePrecision{<:AbstractFloat} ,
1281+ y:: Union{ComplexFloat,TwicePrecision{<:ComplexFloat}} ,
1282+ ) =
1283+ # TODO : evaluate whether it makes sense to write custom code
1284+ # TODO : try preventing some overflows and underflows?
1285+ div_complex_twiceprec_impl (x, y)
1286+
1287+ / (
1288+ x:: AbstractFloat ,
1289+ y:: TwicePrecision{<:ComplexFloat} ,
1290+ ) =
1291+ # TODO : evaluate whether it makes sense to write custom code
1292+ # TODO : try preventing some overflows and underflows?
1293+ div_complex_twiceprec_impl (x, y)
1294+
1295+ function / (
1296+ x:: TwicePrecision{<:ComplexFloat} ,
1297+ y:: Union{AbstractFloat,TwicePrecision{<:AbstractFloat}} ,
1298+ )
1299+ x_re = real (x)
1300+ x_im = imag (x)
1301+ res_re = x_re / y
1302+ res_im = x_im / y
1303+ complex_twiceprec (res_re, res_im)
1304+ end
1305+
1306+ / (x:: Tw , y:: Union{T,Tw} ) where {T<: ComplexFloat ,Tw<: TwicePrecision{T} } =
1307+ # TODO : evaluate whether it makes sense to write custom code
1308+ # TODO : try preventing some overflows and underflows?
1309+ div_complex_twiceprec_impl (x, y)
1310+
1311+ / (x:: ComplexFloat , y:: TwicePrecision{<:ComplexFloat} ) =
1312+ # TODO : evaluate whether it makes sense to write custom code
1313+ # TODO : try preventing some overflows and underflows?
1314+ div_complex_twiceprec_impl (x, y)
0 commit comments