mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[expressions] Make int/int return double results.
Also add a new "//" operator to perform integer division. (fix #5153)
This commit is contained in:
parent
26e06e6881
commit
232aaaca66
@ -150,6 +150,7 @@ class QgsExpression
|
||||
boMinus,
|
||||
boMul,
|
||||
boDiv,
|
||||
boIntDiv,
|
||||
boMod,
|
||||
boPow,
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QDomDocument>
|
||||
#include <QSettings>
|
||||
#include <QDate>
|
||||
#include <QRegExp>
|
||||
#include <QColor>
|
||||
@ -2173,14 +2172,14 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, const Q
|
||||
case boMul:
|
||||
case boDiv:
|
||||
case boMod:
|
||||
{
|
||||
if ( isNull( vL ) || isNull( vR ) )
|
||||
return QVariant();
|
||||
else if ( isIntSafe( vL ) && isIntSafe( vR ) )
|
||||
else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
|
||||
{
|
||||
// both are integers - let's use integer arithmetics
|
||||
int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
|
||||
int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
|
||||
if ( mOp == boDiv && iR == 0 ) return QVariant(); // silently handle division by zero and return NULL
|
||||
return QVariant( computeInt( iL, iR ) );
|
||||
}
|
||||
else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
|
||||
@ -2203,7 +2202,16 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, const Q
|
||||
return QVariant(); // silently handle division by zero and return NULL
|
||||
return QVariant( computeDouble( fL, fR ) );
|
||||
}
|
||||
|
||||
}
|
||||
case boIntDiv:
|
||||
{
|
||||
//integer division
|
||||
double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
|
||||
double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
|
||||
if ( fR == 0 )
|
||||
return QVariant(); // silently handle division by zero and return NULL
|
||||
return QVariant( qFloor( fL / fR ) );
|
||||
}
|
||||
case boPow:
|
||||
if ( isNull( vL ) || isNull( vR ) )
|
||||
return QVariant();
|
||||
@ -2421,6 +2429,7 @@ int QgsExpression::NodeBinaryOperator::precedence() const
|
||||
|
||||
case boMul:
|
||||
case boDiv:
|
||||
case boIntDiv:
|
||||
case boMod:
|
||||
return 5;
|
||||
|
||||
|
@ -241,6 +241,7 @@ class CORE_EXPORT QgsExpression
|
||||
boMinus,
|
||||
boMul,
|
||||
boDiv,
|
||||
boIntDiv,
|
||||
boMod,
|
||||
boPow,
|
||||
|
||||
|
@ -155,6 +155,7 @@ string "'"{str_char}*"'"
|
||||
"+" { B_OP(boPlus); return PLUS; }
|
||||
"-" { B_OP(boMinus); return MINUS; }
|
||||
"*" { B_OP(boMul); return MUL; }
|
||||
"//" { B_OP(boIntDiv); return INTDIV; }
|
||||
"/" { B_OP(boDiv); return DIV; }
|
||||
"%" { B_OP(boMod); return MOD; }
|
||||
"^" { B_OP(boPow); return POW; }
|
||||
|
@ -94,7 +94,7 @@ struct expression_parser_context
|
||||
//
|
||||
|
||||
// operator tokens
|
||||
%token <b_op> OR AND EQ NE LE GE LT GT REGEXP LIKE IS PLUS MINUS MUL DIV MOD CONCAT POW
|
||||
%token <b_op> OR AND EQ NE LE GE LT GT REGEXP LIKE IS PLUS MINUS MUL DIV INTDIV MOD CONCAT POW
|
||||
%token <u_op> NOT
|
||||
%token IN
|
||||
|
||||
@ -136,7 +136,7 @@ struct expression_parser_context
|
||||
%right NOT
|
||||
%left EQ NE LE GE LT GT REGEXP LIKE IS IN
|
||||
%left PLUS MINUS
|
||||
%left MUL DIV MOD
|
||||
%left MUL DIV INTDIV MOD
|
||||
%right POW
|
||||
%left CONCAT
|
||||
|
||||
@ -168,6 +168,7 @@ expression:
|
||||
| expression PLUS expression { $$ = BINOP($2, $1, $3); }
|
||||
| expression MINUS expression { $$ = BINOP($2, $1, $3); }
|
||||
| expression MUL expression { $$ = BINOP($2, $1, $3); }
|
||||
| expression INTDIV expression { $$ = BINOP($2, $1, $3); }
|
||||
| expression DIV expression { $$ = BINOP($2, $1, $3); }
|
||||
| expression MOD expression { $$ = BINOP($2, $1, $3); }
|
||||
| expression POW expression { $$ = BINOP($2, $1, $3); }
|
||||
|
@ -172,7 +172,7 @@ class TestQgsExpression: public QObject
|
||||
QTest::newRow( "plus invalid" ) << "1+'foo'" << true << QVariant();
|
||||
QTest::newRow( "minus int" ) << "1-3" << false << QVariant( -2 );
|
||||
QTest::newRow( "mul int" ) << "8*7" << false << QVariant( 56 );
|
||||
QTest::newRow( "div int" ) << "20/6" << false << QVariant( 3 );
|
||||
QTest::newRow( "div int" ) << "5/2" << false << QVariant( 2.5 );
|
||||
QTest::newRow( "mod int" ) << "20%6" << false << QVariant( 2 );
|
||||
QTest::newRow( "minus double" ) << "5.2-3.1" << false << QVariant( 2.1 );
|
||||
QTest::newRow( "mul double" ) << "2.1*5" << false << QVariant( 10.5 );
|
||||
@ -181,6 +181,12 @@ class TestQgsExpression: public QObject
|
||||
QTest::newRow( "pow" ) << "2^8" << false << QVariant( 256. );
|
||||
QTest::newRow( "division by zero" ) << "1/0" << false << QVariant();
|
||||
QTest::newRow( "division by zero" ) << "1.0/0.0" << false << QVariant();
|
||||
QTest::newRow( "int division" ) << "5//2" << false << QVariant( 2 );
|
||||
QTest::newRow( "int division with doubles" ) << "5.0//2.0" << false << QVariant( 2 );
|
||||
QTest::newRow( "negative int division" ) << "-5//2" << false << QVariant( -3 );
|
||||
QTest::newRow( "negative int division with doubles" ) << "-5.0//2.0" << false << QVariant( -3 );
|
||||
QTest::newRow( "int division by zero" ) << "1//0" << false << QVariant();
|
||||
QTest::newRow( "int division by zero with floats" ) << "1.0//0.0" << false << QVariant();
|
||||
|
||||
// comparison
|
||||
QTest::newRow( "eq int" ) << "1+1 = 2" << false << QVariant( 1 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user