changed float handling and appropriate compiler messages

This commit is contained in:
Irmen de Jong 2018-09-25 19:52:59 +02:00
parent d990b05998
commit 53cd50ad48
8 changed files with 42 additions and 45 deletions

View File

@ -25,11 +25,9 @@
flt(44) flt(44)
for pixely in yoffset to yoffset+height-1 { for pixely in yoffset to yoffset+height-1 {
; yy = (pixely-yoffset)/height/3.6+0.4 ; @todo compiler float error
yy = flt((pixely-yoffset))/height/3.6+0.4 yy = flt((pixely-yoffset))/height/3.6+0.4
for pixelx in xoffset to xoffset+width-1 { for pixelx in xoffset to xoffset+width-1 {
; xx = (pixelx-xoffset)/width/3+0.2 ; @todo compiler float error
xx = flt((pixelx-xoffset))/width/3+0.2 xx = flt((pixelx-xoffset))/width/3+0.2
x = 0.0 x = 0.0

View File

@ -4,41 +4,26 @@
sub start() -> () { sub start() -> () {
byte i=2 byte i
float f
word ww = $55aa
set_carry() float yy
clear_carry() word pixely
set_irqd() word yoffset
clear_irqd() word height
f=flt(i)
i = msb(ww)
i = lsb(ww)
lsl(i)
lsr(i)
rol(i)
ror(i)
rol2(i)
ror2(i)
; @todo expression must not result in float but in word
while i<10 { yy = flt(height+1.1)
_vm_write_num(i) pixely = height / 100
_vm_write_char($8d) ;yy = height- 1.1
i++ ;yy = height*1.1
} ;yy = height/3.6
;yy = height//3.6
_vm_write_char($8d) ;yy = height**3.6
;yy = height%3.6
i=2 ;yy = height/3.6+0.4
repeat { ;yy = 2/height/3.6+0.4
_vm_write_num(i) ;yy = (pixely-yoffset)/height/3.6+0.4
_vm_write_char($8d)
i++
} until i>10
} }
} }

View File

@ -725,8 +725,7 @@ class BinaryExpression(var left: IExpression, val operator: String, var right: I
val leftDt = left.resultingDatatype(namespace) val leftDt = left.resultingDatatype(namespace)
val rightDt = right.resultingDatatype(namespace) val rightDt = right.resultingDatatype(namespace)
return when(operator) { return when(operator) {
"+", "-", "*", "**", "%" -> if(leftDt==null || rightDt==null) null else arithmeticOpDt(leftDt, rightDt) "+", "-", "*", "**", "/", "%" -> if(leftDt==null || rightDt==null) null else arithmeticOpDt(leftDt, rightDt)
"/" -> if(leftDt==null || rightDt==null) null else DataType.FLOAT
"//" -> if(leftDt==null || rightDt==null) null else integerDivisionOpDt(leftDt, rightDt) "//" -> if(leftDt==null || rightDt==null) null else integerDivisionOpDt(leftDt, rightDt)
"&" -> leftDt "&" -> leftDt
"|" -> leftDt "|" -> leftDt

View File

@ -722,7 +722,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
if(sourceDatatype==DataType.WORD && targetDatatype==DataType.BYTE) if(sourceDatatype==DataType.WORD && targetDatatype==DataType.BYTE)
checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position)) checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position))
else if(sourceDatatype==DataType.FLOAT && (targetDatatype==DataType.BYTE || targetDatatype==DataType.WORD)) else if(sourceDatatype==DataType.FLOAT && (targetDatatype==DataType.BYTE || targetDatatype==DataType.WORD))
checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}; possible loss of precision", position)) checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.toString().toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position))
else else
checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position)) checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position))

View File

@ -289,6 +289,15 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
stackvmProg.instr(Opcode.NOP) stackvmProg.instr(Opcode.NOP)
} }
private fun checkForFloatPrecisionProblem(left: IExpression, right: IExpression) {
val leftDt = left.resultingDatatype(namespace)
val rightDt = right.resultingDatatype(namespace)
if (leftDt == DataType.BYTE || leftDt == DataType.WORD) {
if(rightDt==DataType.FLOAT)
printWarning("byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion or revert to integer arithmetic", left.position)
}
}
private fun translate(expr: IExpression) { private fun translate(expr: IExpression) {
when(expr) { when(expr) {
is RegisterExpr -> { is RegisterExpr -> {
@ -299,6 +308,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
translatePrefixOperator(expr.operator) translatePrefixOperator(expr.operator)
} }
is BinaryExpression -> { is BinaryExpression -> {
checkForFloatPrecisionProblem(expr.left, expr.right)
translate(expr.left) translate(expr.left)
translate(expr.right) translate(expr.right)
translateBinaryOperator(expr.operator) translateBinaryOperator(expr.operator)

View File

@ -7,7 +7,7 @@ import prog8.ast.Module
import prog8.parser.ParsingFailedError import prog8.parser.ParsingFailedError
/** /**
* TODO: array, matrix, string and float constants should be put into a constant-pool * TODO: array, matrix, string and float constants should be put into a constant-pool,
* so that they're only stored once instead of replicated everywhere. * so that they're only stored once instead of replicated everywhere.
* Note that initial constant folding of them is fine: it's needed to be able to * Note that initial constant folding of them is fine: it's needed to be able to
* optimize the expressions. But as a final step, they should be consolidated again * optimize the expressions. But as a final step, they should be consolidated again

View File

@ -1178,7 +1178,7 @@ class TestStackVmOpcodes {
@Test @Test
fun testReturn() { fun testReturn() {
// @todo only tests return with zero return values // @todo this only tests return with zero return values for now.
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.RETURN), Instruction(Opcode.RETURN),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
@ -1199,7 +1199,7 @@ class TestStackVmOpcodes {
@Test @Test
fun testCall() { fun testCall() {
// @todo only tests call with zero parameters // @todo this only tests call with zero parameters for now.
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.CALL, callLabel = "label"), Instruction(Opcode.CALL, callLabel = "label"),
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "returned")), Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "returned")),

View File

@ -372,7 +372,7 @@ for normal assignments (``A = A + X``).
The reverse is *not* true: it is *not* possible to assign a value of a 'larger' datatype to The reverse is *not* true: it is *not* possible to assign a value of a 'larger' datatype to
a variable of a smaller datatype without an explicit conversion. Otherwise you'll get an error telling you a variable of a smaller datatype without an explicit conversion. Otherwise you'll get an error telling you
that there is a loss of precision. You can use builtin functions such as ``round`` and ``lsb`` to convert that there is a loss of precision. You can use builtin functions such as ``round`` and ``lsb`` to convert
to a smaller datatype. to a smaller datatype, or revert to integer arithmetic.
Expressions Expressions
----------- -----------
@ -385,13 +385,18 @@ There are various built-in functions such as sin(), cos(), min(), max() that can
You can also reference idendifiers defined elsewhere in your code. You can also reference idendifiers defined elsewhere in your code.
.. attention:: .. attention::
**Data type conversion (during calculations):** **Data type conversion (during calculations) and floating point handling:**
BYTE values used in arithmetic expressions (calculations) will be automatically converted into WORD values BYTE values used in arithmetic expressions (calculations) will be automatically converted into WORD values
if the calculation needs that to store the resulting value. Once a WORD value is used, all other results will be WORDs as well if the calculation needs that to store the resulting value. Once a WORD value is used, all other results will be WORDs as well
(there's no automatic conversion of WORD into BYTE). (there's no automatic conversion of WORD into BYTE).
*There is never an automatic conversion into floating point values, and the compiler will NOT issue a warning for this.*
If you require float precision, you'll have to first convert into a floating point explicitly using the ``flt`` builtin function. When a floating point value is used in a calculation, the result will be a floating point, and byte or word values
For example, this means that if you divide two integer values (say: ``32500 / 99``) the result will be the integer floor will be automatically converted into floats in this case. The compiler will issue a warning though when this happens, because floating
point calculations are very slow and possibly unintended!
Calculations with integers will not result in floating point values;
if you divide two integer values (say: ``32500 / 99``) the result will be the integer floor
division (328) rather than the floating point result (328.2828282828283). If you need the full precision, division (328) rather than the floating point result (328.2828282828283). If you need the full precision,
you'll have to write ``flt(32500) / 99`` (or if they're constants, simply ``32500.0 / 99``), to make sure the you'll have to write ``flt(32500) / 99`` (or if they're constants, simply ``32500.0 / 99``), to make sure the
first operand is a floating point value. first operand is a floating point value.