Commit a63ec075 authored by BenceJanosSzabo's avatar BenceJanosSzabo
Browse files

Corrected +-infinity and NaN in arithmetic expressions: everything allowed



Change-Id: Idfa5b6c28c525d5b3d6b67ca740851be84ee9727
Signed-off-by: default avatarBenceJanosSzabo <bence.janos.szabo@ericsson.com>
parent f22c2af3
......@@ -32,11 +32,6 @@ namespace Common {
{
return ((r!=r) || (r==REAL_INFINITY) || (r==-REAL_INFINITY));
}
bool isNaN(const Real& r)
{
return r!=r;
}
string Real2string(const Real& r)
{
......
......@@ -55,7 +55,6 @@ namespace Common {
/** +/- infinity and not_a_number are non-numeric float values in ttcn-3,
these special values cannot be used in some places */
bool isSpecialFloatValue(const Real& r);
bool isNaN(const Real& r);
/**
* Converts the Common::Real value to string.
......
......@@ -6396,47 +6396,6 @@ error:
set_valuetype(V_ERROR);
}
}
void Value::chk_expr_operand_valid_float(Value* v1, Value* v2, const char *opnum1, const char *opnum2, const char *opname)
{
ttcn3float r1, r2;
boolean r1_is_set = FALSE, r2_is_set = FALSE;
if(valuetype!=V_ERROR) {
if(u.expr.state!=EXPR_CHECKING_ERR) {
if(!v1->is_unfoldable()) {
if(v1->get_expr_returntype()==Type::T_REAL) {
r1 = v1->get_val_Real();
r1_is_set = TRUE;
}
}
if(!v2->is_unfoldable()) {
if(v2->get_expr_returntype()==Type::T_REAL) {
r2 = v2->get_val_Real();
r2_is_set = TRUE;
}
}
if (r1_is_set && r2_is_set) {
if ((isSpecialFloatValue(r1) && isSpecialFloatValue(r2)) || isNaN(r1) || isNaN(r2)) {
error("Invalid operands of float %s: %s operand is %s, %s operand is %s",
opname, opnum1, Real2string(r1).c_str(), opnum2, Real2string(r2).c_str());
set_valuetype(V_ERROR);
}
} else if (r1_is_set) {
if (isNaN(r1)) {
v1->error("%s operand of operation `%s' cannot be %s, it must be a numeric value",
opnum1, opname, Real2string(r1).c_str());
set_valuetype(V_ERROR);
}
} else if (r2_is_set) {
if (isNaN(r2)) {
v2->error("%s operand of operation `%s' cannot be %s, it must be a numeric value",
opnum2, opname, Real2string(r2).c_str());
set_valuetype(V_ERROR);
}
}
}
}
}
void Value::chk_expr_operands(ReferenceChain *refch,
Type::expected_value_t exp_val)
......@@ -6943,7 +6902,7 @@ error:
chk_expr_operandtype_int_float(tt2, second, opname, v2);
chk_expr_eval_value(v1, t_chk, refch, exp_val);
chk_expr_eval_value(v2, t_chk, refch, exp_val);
chk_expr_operand_valid_float(v1, v2, first, second, opname);
// No float checks needed, everything is allowed on -+infinity and not_a_number
if(u.expr.v_optype==OPTYPE_DIVIDE)
chk_expr_val_int_float_not0(v2, second, opname);
chk_expr_operandtypes_same(tt1, tt2, opname);
......
......@@ -668,7 +668,6 @@ namespace Common {
void chk_expr_operands(ReferenceChain *refch,
Type::expected_value_t exp_val);
void chk_expr_operand_valid_float(Value* v, const char *opnum, const char *opname);
void chk_expr_operand_valid_float(Value* v1, Value* v2, const char *opnum1, const char *opnum2, const char *opname);
/** Evaluate...
* Called by Value::get_value_refd_last() for V_EXPR */
void evaluate_value(ReferenceChain *refch, Type::expected_value_t exp_val);
......
......@@ -77,4 +77,4 @@ const char * XSD_type_to_xml_type(const XSD_types xsd_type);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*XSD_TYPES_HH*/
\ No newline at end of file
#endif /*XSD_TYPES_HH*/
......@@ -130,11 +130,6 @@ boolean FLOAT::is_special(double flt_val)
return ( (flt_val!=flt_val) || (flt_val==INFINITY) || (flt_val==-INFINITY) );
}
boolean FLOAT::is_nan(double flt_val)
{
return flt_val!=flt_val;
}
void FLOAT::check_numeric(double flt_val, const char *err_msg_begin)
{
if (is_special(flt_val)) {
......@@ -146,10 +141,6 @@ void FLOAT::check_numeric(double flt_val, const char *err_msg_begin)
double FLOAT::operator+(double other_value) const
{
must_bound("Unbound left operand of float addition.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) {
TTCN_error("Invalid operands of float addition: Left operand is %g, right operand is %g", (double)float_value, other_value);
}
return float_value + other_value;
}
......@@ -157,20 +148,12 @@ double FLOAT::operator+(const FLOAT& other_value) const
{
must_bound("Unbound left operand of float addition.");
other_value.must_bound("Unbound right operand of float addition.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float addition: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value);
}
return float_value + other_value.float_value;
}
double FLOAT::operator-(double other_value) const
{
must_bound("Unbound left operand of float subtraction.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) {
TTCN_error("Invalid operands of float subtraction: Left operand is %g, right operand is %g", (double)float_value, other_value);
}
return float_value - other_value;
}
......@@ -178,20 +161,12 @@ double FLOAT::operator-(const FLOAT& other_value) const
{
must_bound("Unbound left operand of float subtraction.");
other_value.must_bound("Unbound right operand of float subtraction.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float subtraction: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value);
}
return float_value - other_value.float_value;
}
double FLOAT::operator*(double other_value) const
{
must_bound("Unbound left operand of float multiplication.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) {
TTCN_error("Invalid operands of float multiplication: Left operand is %g, right operand is %g", (double)float_value, other_value);
}
return float_value * other_value;
}
......@@ -199,20 +174,12 @@ double FLOAT::operator*(const FLOAT& other_value) const
{
must_bound("Unbound left operand of float multiplication.");
other_value.must_bound("Unbound right operand of float multiplication.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float multiplication: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value);
}
return float_value * other_value.float_value;
}
double FLOAT::operator/(double other_value) const
{
must_bound("Unbound left operand of float division.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) {
TTCN_error("Invalid operands of float division: Left operand is %g, right operand is %g", (double)float_value, other_value);
}
if (other_value == 0.0) TTCN_error("Float division by zero.");
return float_value / other_value;
}
......@@ -221,10 +188,6 @@ double FLOAT::operator/(const FLOAT& other_value) const
{
must_bound("Unbound left operand of float division.");
other_value.must_bound("Unbound right operand of float division.");
// Both of them are +-infinity or one of them is nan
if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float division: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value);
}
if (other_value.float_value == 0.0) TTCN_error("Float division by zero.");
return float_value / other_value.float_value;
}
......@@ -1195,40 +1158,24 @@ int FLOAT::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok,
double operator+(double double_value, const FLOAT& other_value)
{
other_value.must_bound("Unbound right operand of float addition.");
// Both of them are +-infinity or one of them is nan
if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float addition: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value);
}
return double_value + other_value.float_value;
}
double operator-(double double_value, const FLOAT& other_value)
{
other_value.must_bound("Unbound right operand of float subtraction.");
// Both of them are +-infinity or one of them is nan
if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float subtraction: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value);
}
return double_value - other_value.float_value;
}
double operator*(double double_value, const FLOAT& other_value)
{
other_value.must_bound("Unbound right operand of float multiplication.");
// Both of them are +-infinity or one of them is nan
if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float multiplication: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value);
}
return double_value * other_value.float_value;
}
double operator/(double double_value, const FLOAT& other_value)
{
other_value.must_bound("Unbound right operand of float division.");
// Both of them are +-infinity or one of them is nan
if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) {
TTCN_error("Invalid operands of float division: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value);
}
if (other_value.float_value == 0.0) TTCN_error("Float division by zero.");
return double_value / other_value.float_value;
}
......
......@@ -106,7 +106,6 @@ public:
/** special TTCN-3 float values are not_a_number and +/- infinity */
static boolean is_special(double flt_val);
static boolean is_nan(double flt_val);
static void check_numeric(double flt_val, const char *err_msg_begin);
void log() const;
......
......@@ -6536,9 +6536,6 @@ control {
}
<END_MODULE>
<RESULT IF_PASS COUNT 1>
(?im)error: Second operand of operation `/' cannot be NaN, it must be a numeric value
<END_RESULT>
<RESULT IF_PASS COUNT 1>
(?im)error: The operand of operation `rnd \(seed\)' cannot be INF, it must be a numeric value
<END_RESULT>
<RESULT IF_PASS COUNT 1>
......@@ -6550,7 +6547,7 @@ control {
<RESULT IF_PASS COUNT 1>
(?im)error: A non-negative float value was expected as timer duration instead of `NaN'
<END_RESULT>
<RESULT IF_PASS COUNT 5>
<RESULT IF_PASS COUNT 4>
(?is)\berror:
<END_RESULT>
<END_TC>
......
/******************************************************************************
* Copyright (c) 2000-2016 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bence Janos Szabo
*
******************************************************************************/
module special_SE {
const float err1 := infinity + infinity;
const float err2 := infinity + -infinity;
const float err3 := -infinity + -infinity;
const float err4 := infinity - infinity;
const float err5 := infinity - -infinity;
const float err6 := -infinity - -infinity;
const float err7 := infinity * infinity;
const float err8 := infinity * -infinity;
const float err9 := -infinity * -infinity;
const float err10 := infinity / infinity;
const float err11 := infinity / -infinity;
const float err12 := -infinity / -infinity;
const float err13 := not_a_number + 2.0;
const float err14 := not_a_number - 2.0;
const float err15 := not_a_number * 2.0;
const float err16 := not_a_number / 2.0;
const float err17 := not_a_number + infinity;
const float err18 := not_a_number + -infinity;
function fun() {
var float f := 2.0;
var float f2 := f + not_a_number;
f2 := not_a_number + f;
f2 := not_a_number - f;
f2 := f - not_a_number;
f2 := not_a_number * f;
f2 := f * not_a_number;
f2 := not_a_number / f;
f2 := f / not_a_number;
}
}
/******************************************************************************
* Copyright (c) 2000-2016 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bence Janos Szabo
*
******************************************************************************/
module special_SE { //^In TTCN-3 module//
const float err1 := infinity + infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is INF\, Second operand is INF//
const float err2 := infinity + -infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is INF\, Second operand is -INF//
const float err3 := -infinity + -infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is -INF\, Second operand is -INF//
const float err4 := infinity - infinity; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is INF\, Second operand is INF//
const float err5 := infinity - -infinity; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is INF\, Second operand is -INF//
const float err6 := -infinity - -infinity; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is -INF\, Second operand is -INF//
const float err7 := infinity * infinity; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is INF\, Second operand is INF//
const float err8 := infinity * -infinity; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is INF\, Second operand is -INF//
const float err9 := -infinity * -infinity; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is -INF\, Second operand is -INF//
const float err10 := infinity / infinity; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is INF\, Second operand is INF//
const float err11 := infinity / -infinity; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is INF\, Second operand is -INF//
const float err12 := -infinity / -infinity; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is -INF\, Second operand is -INF//
const float err13 := not_a_number + 2.0; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is NaN\, Second operand is 2\.0e0//
const float err14 := not_a_number - 2.0; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is NaN\, Second operand is 2\.0e0//
const float err15 := not_a_number * 2.0; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is NaN\, Second operand is 2\.0e0//
const float err16 := not_a_number / 2.0; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is NaN\, Second operand is 2\.0e0//
const float err17 := not_a_number + infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is NaN\, Second operand is INF//
const float err18 := not_a_number + -infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is NaN\, Second operand is -INF//
function fun() { //^In function definition//
var float f := 2.0;
var float f2 := f + not_a_number; //^In variable definition// //^In the operands of operation \`\+\'// //^error: Second operand of operation \`\+\' cannot be NaN\, it must be a numeric value//
f2 := not_a_number + f; //^In variable assignment// //^In the operands of operation \`\+\'// //^error: First operand of operation \`\+\' cannot be NaN\, it must be a numeric value//
f2 := not_a_number - f; //^In variable assignment// //^In the operands of operation \`\-\'// //^error: First operand of operation \`\-\' cannot be NaN\, it must be a numeric value//
f2 := f - not_a_number; //^In variable assignment// //^In the operands of operation \`\-\'// //^error: Second operand of operation \`\-\' cannot be NaN\, it must be a numeric value//
f2 := not_a_number * f; //^In variable assignment// //^In the operands of operation \`\*\'// //^error: First operand of operation \`\*\' cannot be NaN\, it must be a numeric value//
f2 := f * not_a_number; //^In variable assignment// //^In the operands of operation \`\*\'// //^error: Second operand of operation \`\*\' cannot be NaN\, it must be a numeric value//
f2 := not_a_number / f; //^In variable assignment// //^In the operands of operation \`\/\'// //^error: First operand of operation \`\/\' cannot be NaN\, it must be a numeric value//
f2 := f / not_a_number; //^In variable assignment// //^In the operands of operation \`\/\'// //^error: Second operand of operation \`\/\' cannot be NaN\, it must be a numeric value//
}
}
......@@ -37,7 +37,11 @@ testcase tc_addition() runs on EmptyCT {
setverdict(fail);
}
// Checked at compile time
f := f2 + f;
if (f != -infinity) {
setverdict(fail);
}
f := infinity + 1.0;
if (f != infinity) {
setverdict(fail);
......@@ -48,109 +52,38 @@ testcase tc_addition() runs on EmptyCT {
setverdict(fail);
}
var charstring dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is inf, right operand is inf";
@try {
f := infinity;
f2 := infinity;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
}
dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is inf, right operand is -inf";
@try {
f := infinity;
f2 := -infinity;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
}
dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is -inf, right operand is inf";
@try {
f := -infinity;
f2 := infinity;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := not_a_number + f2;
if (f != not_a_number) {
setverdict(fail);
}
dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is -inf, right operand is -inf";
@try {
f := -infinity;
f2 := -infinity;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := f2 + not_a_number;
if (f != not_a_number) {
setverdict(fail);
}
dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is nan, right operand is inf";
@try {
f := not_a_number;
f2 := infinity;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := infinity + not_a_number;
if (f != not_a_number) {
setverdict(fail);
}
dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is inf, right operand is nan";
@try {
f := infinity;
f2 := not_a_number;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := -infinity + not_a_number;
if (f != not_a_number) {
setverdict(fail);
}
dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is nan, right operand is nan";
@try {
f := not_a_number;
f2 := not_a_number;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := -infinity + infinity;
if (f != not_a_number) {
setverdict(fail);
}
dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is nan, right operand is 1";
@try {
f := not_a_number;
f2 := 1.0;
f := f + f2;
setverdict(fail, "Expected dynamic test case error");
f := infinity + infinity;
if (f != infinity) {
setverdict(fail);
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := -infinity + -infinity;
if (f != -infinity) {
setverdict(fail);
}
setverdict(pass);
......@@ -169,6 +102,10 @@ testcase tc_subtraction() runs on EmptyCT {
setverdict(fail);
}
f := f2 - f;
if (f != -infinity) {
setverdict(fail);
}
f := -infinity;
f := f - 1.0;
......@@ -180,7 +117,6 @@ testcase tc_subtraction() runs on EmptyCT {
setverdict(fail);
}
// Checked at compile time
f := infinity - 1.0;
if (f != infinity) {
setverdict(fail);
......@@ -192,108 +128,39 @@ testcase tc_subtraction() runs on EmptyCT {
}
var charstring dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is inf, right operand is inf";
@try {
f := infinity;
f2 := infinity;
f := f - f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
}
dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is inf, right operand is -inf";
@try {
f := infinity;
f2 := -infinity;
f := f - f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := not_a_number - f2;
if (f != not_a_number) {
setverdict(fail);
}
dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is -inf, right operand is inf";
@try {
f := -infinity;
f2 := infinity;
f := f - f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := f2 - not_a_number;
if (f != not_a_number) {
setverdict(fail);
}
dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is -inf, right operand is -inf";
@try {
f := -infinity;
f2 := -infinity;
f := f - f2;
setverdict(fail, "Expected dynamic test case error");
}
@catch (msg) {
if (not match(msg, dte_message)) {
setverdict(fail, "Expected error: ", dte_message, ", got: ", msg);
}
f := infinity - not_a_number;
if (f != not_a_number) {
setverdict(fail);
}