Bytecode: add missing floating point exception handling for sqrt and several trigonometric functions

silicon
Sébastien Villemot 2023-04-07 17:28:07 +02:00
parent 2740bdee58
commit 9f29e2f292
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
2 changed files with 69 additions and 35 deletions

View File

@ -41,28 +41,14 @@ struct FloatingPointException : public GeneralException
}
};
struct LogException : public FloatingPointException
struct UnaryOpException : public FloatingPointException
{
LogException(double value, string location_arg) :
UnaryOpException(const string &op, double value, string location_arg) :
FloatingPointException { [=]
{
// We dont use std::to_string(), because it uses fixed formatting
ostringstream s;
s << "log(X) with X=" << defaultfloat << value;
return s.str();
}(), move(location_arg) }
{
}
};
struct Log10Exception : public FloatingPointException
{
Log10Exception(double value, string location_arg) :
FloatingPointException { [=]
{
// We dont use std::to_string(), because it uses fixed formatting
ostringstream s;
s << "log10(X) with X=" << defaultfloat << value;
s << op << "(X) with X=" << defaultfloat << value;
return s.str();
}(), move(location_arg) }
{

View File

@ -643,27 +643,27 @@ Evaluate::print_expression(const Evaluate::it_code_type &expr_begin, const optio
case UnaryOpcode::sin:
return "sin";
case UnaryOpcode::tan:
return "tan";
return it_code == faulty_op ? "{tan}" : "tan";
case UnaryOpcode::acos:
return "acos";
return it_code == faulty_op ? "{acos}" : "acos";
case UnaryOpcode::asin:
return "asin";
return it_code == faulty_op ? "{asin}" : "asin";
case UnaryOpcode::atan:
return "atan";
case UnaryOpcode::cosh:
return "cosh";
return it_code == faulty_op ? "{cosh}" : "cosh";
case UnaryOpcode::sinh:
return "sinh";
return it_code == faulty_op ? "{sinh}" : "sinh";
case UnaryOpcode::tanh:
return "tanh";
case UnaryOpcode::acosh:
return "acosh";
return it_code == faulty_op ? "{acosh}" : "acosh";
case UnaryOpcode::asinh:
return "asinh";
case UnaryOpcode::atanh:
return "atanh";
return it_code == faulty_op ? "{atanh}" : "atanh";
case UnaryOpcode::sqrt:
return "sqrt";
return it_code == faulty_op ? "{sqrt}" : "sqrt";
case UnaryOpcode::cbrt:
return "cbrt";
case UnaryOpcode::erf:
@ -1699,7 +1699,7 @@ Evaluate::evaluateBlock(int Per_u_, bool evaluate, bool no_derivative)
feclearexcept(FE_ALL_EXCEPT);
double tmp {log(v1)};
if (fetestexcept(FE_DIVBYZERO | FE_INVALID))
throw LogException{v1, error_location(it_code_expr, it_code, steady_state, it_)};
throw UnaryOpException{"log", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
@ -1711,7 +1711,7 @@ Evaluate::evaluateBlock(int Per_u_, bool evaluate, bool no_derivative)
feclearexcept(FE_ALL_EXCEPT);
double tmp {log10(v1)};
if (fetestexcept(FE_DIVBYZERO | FE_INVALID))
throw Log10Exception{v1, error_location(it_code_expr, it_code, steady_state, it_)};
throw UnaryOpException{"log10", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
@ -1731,19 +1731,37 @@ Evaluate::evaluateBlock(int Per_u_, bool evaluate, bool no_derivative)
#endif
break;
case UnaryOpcode::tan:
Stack.push(tan(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {tan(v1)};
if (fetestexcept(FE_OVERFLOW))
throw UnaryOpException{"tan", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |tan(" << v1 << ")|";
#endif
break;
case UnaryOpcode::acos:
Stack.push(acos(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {acos(v1)};
if (fetestexcept(FE_INVALID))
throw UnaryOpException{"acos", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |acos(" << v1 << ")|";
#endif
break;
case UnaryOpcode::asin:
Stack.push(asin(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {asin(v1)};
if (fetestexcept(FE_INVALID))
throw UnaryOpException{"asin", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |asin(" << v1 << ")|";
#endif
@ -1755,13 +1773,25 @@ Evaluate::evaluateBlock(int Per_u_, bool evaluate, bool no_derivative)
#endif
break;
case UnaryOpcode::cosh:
Stack.push(cosh(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {cosh(v1)};
if (fetestexcept(FE_OVERFLOW))
throw UnaryOpException{"cosh", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |cosh(" << v1 << ")|";
#endif
break;
case UnaryOpcode::sinh:
Stack.push(sinh(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {sinh(v1)};
if (fetestexcept(FE_OVERFLOW))
throw UnaryOpException{"sinh", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |sinh(" << v1 << ")|";
#endif
@ -1773,7 +1803,13 @@ Evaluate::evaluateBlock(int Per_u_, bool evaluate, bool no_derivative)
#endif
break;
case UnaryOpcode::acosh:
Stack.push(acosh(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {acosh(v1)};
if (fetestexcept(FE_INVALID))
throw UnaryOpException{"acosh", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |acosh(" << v1 << ")|";
#endif
@ -1785,13 +1821,25 @@ Evaluate::evaluateBlock(int Per_u_, bool evaluate, bool no_derivative)
#endif
break;
case UnaryOpcode::atanh:
Stack.push(atanh(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {atanh(v1)};
if (fetestexcept(FE_INVALID | FE_DIVBYZERO))
throw UnaryOpException{"atanh", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |atanh(" << v1 << ")|";
#endif
break;
case UnaryOpcode::sqrt:
Stack.push(sqrt(v1));
{
feclearexcept(FE_ALL_EXCEPT);
double tmp {sqrt(v1)};
if (fetestexcept(FE_INVALID))
throw UnaryOpException{"sqrt", v1, error_location(it_code_expr, it_code, steady_state, it_)};
Stack.push(tmp);
}
#ifdef DEBUG
tmp_out << " |sqrt(" << v1 << ")|";
#endif