Skip to content

Commit 232aaac

Browse files
committedDec 6, 2014
[expressions] Make int/int return double results.
Also add a new "//" operator to perform integer division. (fix #5153)
1 parent 26e06e6 commit 232aaac

File tree

6 files changed

+26
-7
lines changed

6 files changed

+26
-7
lines changed
 

‎python/core/qgsexpression.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ class QgsExpression
150150
boMinus,
151151
boMul,
152152
boDiv,
153+
boIntDiv,
153154
boMod,
154155
boPow,
155156

‎src/core/qgsexpression.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
#include <QtDebug>
1919
#include <QDomDocument>
20-
#include <QSettings>
2120
#include <QDate>
2221
#include <QRegExp>
2322
#include <QColor>
@@ -2173,14 +2172,14 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, const Q
21732172
case boMul:
21742173
case boDiv:
21752174
case boMod:
2175+
{
21762176
if ( isNull( vL ) || isNull( vR ) )
21772177
return QVariant();
2178-
else if ( isIntSafe( vL ) && isIntSafe( vR ) )
2178+
else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
21792179
{
21802180
// both are integers - let's use integer arithmetics
21812181
int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
21822182
int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2183-
if ( mOp == boDiv && iR == 0 ) return QVariant(); // silently handle division by zero and return NULL
21842183
return QVariant( computeInt( iL, iR ) );
21852184
}
21862185
else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
@@ -2203,7 +2202,16 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, const Q
22032202
return QVariant(); // silently handle division by zero and return NULL
22042203
return QVariant( computeDouble( fL, fR ) );
22052204
}
2206-
2205+
}
2206+
case boIntDiv:
2207+
{
2208+
//integer division
2209+
double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2210+
double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2211+
if ( fR == 0 )
2212+
return QVariant(); // silently handle division by zero and return NULL
2213+
return QVariant( qFloor( fL / fR ) );
2214+
}
22072215
case boPow:
22082216
if ( isNull( vL ) || isNull( vR ) )
22092217
return QVariant();
@@ -2421,6 +2429,7 @@ int QgsExpression::NodeBinaryOperator::precedence() const
24212429

24222430
case boMul:
24232431
case boDiv:
2432+
case boIntDiv:
24242433
case boMod:
24252434
return 5;
24262435

‎src/core/qgsexpression.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ class CORE_EXPORT QgsExpression
241241
boMinus,
242242
boMul,
243243
boDiv,
244+
boIntDiv,
244245
boMod,
245246
boPow,
246247

‎src/core/qgsexpressionlexer.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ string "'"{str_char}*"'"
155155
"+" { B_OP(boPlus); return PLUS; }
156156
"-" { B_OP(boMinus); return MINUS; }
157157
"*" { B_OP(boMul); return MUL; }
158+
"//" { B_OP(boIntDiv); return INTDIV; }
158159
"/" { B_OP(boDiv); return DIV; }
159160
"%" { B_OP(boMod); return MOD; }
160161
"^" { B_OP(boPow); return POW; }

‎src/core/qgsexpressionparser.yy

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct expression_parser_context
9494
//
9595

9696
// operator tokens
97-
%token <b_op> OR AND EQ NE LE GE LT GT REGEXP LIKE IS PLUS MINUS MUL DIV MOD CONCAT POW
97+
%token <b_op> OR AND EQ NE LE GE LT GT REGEXP LIKE IS PLUS MINUS MUL DIV INTDIV MOD CONCAT POW
9898
%token <u_op> NOT
9999
%token IN
100100

@@ -136,7 +136,7 @@ struct expression_parser_context
136136
%right NOT
137137
%left EQ NE LE GE LT GT REGEXP LIKE IS IN
138138
%left PLUS MINUS
139-
%left MUL DIV MOD
139+
%left MUL DIV INTDIV MOD
140140
%right POW
141141
%left CONCAT
142142

@@ -168,6 +168,7 @@ expression:
168168
| expression PLUS expression { $$ = BINOP($2, $1, $3); }
169169
| expression MINUS expression { $$ = BINOP($2, $1, $3); }
170170
| expression MUL expression { $$ = BINOP($2, $1, $3); }
171+
| expression INTDIV expression { $$ = BINOP($2, $1, $3); }
171172
| expression DIV expression { $$ = BINOP($2, $1, $3); }
172173
| expression MOD expression { $$ = BINOP($2, $1, $3); }
173174
| expression POW expression { $$ = BINOP($2, $1, $3); }

‎tests/src/core/testqgsexpression.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class TestQgsExpression: public QObject
172172
QTest::newRow( "plus invalid" ) << "1+'foo'" << true << QVariant();
173173
QTest::newRow( "minus int" ) << "1-3" << false << QVariant( -2 );
174174
QTest::newRow( "mul int" ) << "8*7" << false << QVariant( 56 );
175-
QTest::newRow( "div int" ) << "20/6" << false << QVariant( 3 );
175+
QTest::newRow( "div int" ) << "5/2" << false << QVariant( 2.5 );
176176
QTest::newRow( "mod int" ) << "20%6" << false << QVariant( 2 );
177177
QTest::newRow( "minus double" ) << "5.2-3.1" << false << QVariant( 2.1 );
178178
QTest::newRow( "mul double" ) << "2.1*5" << false << QVariant( 10.5 );
@@ -181,6 +181,12 @@ class TestQgsExpression: public QObject
181181
QTest::newRow( "pow" ) << "2^8" << false << QVariant( 256. );
182182
QTest::newRow( "division by zero" ) << "1/0" << false << QVariant();
183183
QTest::newRow( "division by zero" ) << "1.0/0.0" << false << QVariant();
184+
QTest::newRow( "int division" ) << "5//2" << false << QVariant( 2 );
185+
QTest::newRow( "int division with doubles" ) << "5.0//2.0" << false << QVariant( 2 );
186+
QTest::newRow( "negative int division" ) << "-5//2" << false << QVariant( -3 );
187+
QTest::newRow( "negative int division with doubles" ) << "-5.0//2.0" << false << QVariant( -3 );
188+
QTest::newRow( "int division by zero" ) << "1//0" << false << QVariant();
189+
QTest::newRow( "int division by zero with floats" ) << "1.0//0.0" << false << QVariant();
184190

185191
// comparison
186192
QTest::newRow( "eq int" ) << "1+1 = 2" << false << QVariant( 1 );

0 commit comments

Comments
 (0)
Please sign in to comment.