Computes the power function a^b (f_pow) for f64 values using double–double arithmetic for high precision. It handles different cases for the base 'a': - For a > 0: Computes exp(b * ln(a)). - For a == 0: Handles special cases for 0^b, including returning 0, 1, or a domain error. - For a < 0: Allows only an integer exponent b and adjusts the sign if b is odd.
(&mut self, a: Value, b: Value)
| 1155 | /// - For a == 0: Handles special cases for 0^b, including returning 0, 1, or a domain error. |
| 1156 | /// - For a < 0: Allows only an integer exponent b and adjusts the sign if b is odd. |
| 1157 | fn compile_fpow(&mut self, a: Value, b: Value) -> Value { |
| 1158 | let f64_ty = types::F64; |
| 1159 | let i64_ty = types::I64; |
| 1160 | let zero_f = self.builder.ins().f64const(0.0); |
| 1161 | let one_f = self.builder.ins().f64const(1.0); |
| 1162 | let nan_f = self.builder.ins().f64const(f64::NAN); |
| 1163 | let inf_f = self.builder.ins().f64const(f64::INFINITY); |
| 1164 | let neg_inf_f = self.builder.ins().f64const(f64::NEG_INFINITY); |
| 1165 | |
| 1166 | // Merge block for final result. |
| 1167 | let merge_block = self.builder.create_block(); |
| 1168 | self.builder.append_block_param(merge_block, f64_ty); |
| 1169 | |
| 1170 | // --- Edge Case 1: b == 0.0 → return 1.0 |
| 1171 | let cmp_b_zero = self.builder.ins().fcmp(FloatCC::Equal, b, zero_f); |
| 1172 | let b_zero_block = self.builder.create_block(); |
| 1173 | let continue_block = self.builder.create_block(); |
| 1174 | self.builder |
| 1175 | .ins() |
| 1176 | .brif(cmp_b_zero, b_zero_block, &[], continue_block, &[]); |
| 1177 | self.builder.switch_to_block(b_zero_block); |
| 1178 | self.builder.ins().jump(merge_block, &[one_f.into()]); |
| 1179 | self.builder.switch_to_block(continue_block); |
| 1180 | |
| 1181 | // --- Edge Case 2: b is NaN → return NaN |
| 1182 | let cmp_b_nan = self.builder.ins().fcmp(FloatCC::Unordered, b, b); |
| 1183 | let b_nan_block = self.builder.create_block(); |
| 1184 | let continue_block2 = self.builder.create_block(); |
| 1185 | self.builder |
| 1186 | .ins() |
| 1187 | .brif(cmp_b_nan, b_nan_block, &[], continue_block2, &[]); |
| 1188 | self.builder.switch_to_block(b_nan_block); |
| 1189 | self.builder.ins().jump(merge_block, &[nan_f.into()]); |
| 1190 | self.builder.switch_to_block(continue_block2); |
| 1191 | |
| 1192 | // --- Edge Case 3: a == 0.0 → return 0.0 |
| 1193 | let cmp_a_zero = self.builder.ins().fcmp(FloatCC::Equal, a, zero_f); |
| 1194 | let a_zero_block = self.builder.create_block(); |
| 1195 | let continue_block3 = self.builder.create_block(); |
| 1196 | self.builder |
| 1197 | .ins() |
| 1198 | .brif(cmp_a_zero, a_zero_block, &[], continue_block3, &[]); |
| 1199 | self.builder.switch_to_block(a_zero_block); |
| 1200 | self.builder.ins().jump(merge_block, &[zero_f.into()]); |
| 1201 | self.builder.switch_to_block(continue_block3); |
| 1202 | |
| 1203 | // --- Edge Case 4: a is NaN → return NaN |
| 1204 | let cmp_a_nan = self.builder.ins().fcmp(FloatCC::Unordered, a, a); |
| 1205 | let a_nan_block = self.builder.create_block(); |
| 1206 | let continue_block4 = self.builder.create_block(); |
| 1207 | self.builder |
| 1208 | .ins() |
| 1209 | .brif(cmp_a_nan, a_nan_block, &[], continue_block4, &[]); |
| 1210 | self.builder.switch_to_block(a_nan_block); |
| 1211 | self.builder.ins().jump(merge_block, &[nan_f.into()]); |
| 1212 | self.builder.switch_to_block(continue_block4); |
| 1213 | |
| 1214 | // --- Edge Case 5: b == +infinity → return +infinity |
no test coverage detected