mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
changed float handling and appropriate compiler messages
This commit is contained in:
parent
d990b05998
commit
53cd50ad48
@ -25,11 +25,9 @@
|
||||
|
||||
flt(44)
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
x = 0.0
|
||||
|
@ -4,41 +4,26 @@
|
||||
|
||||
sub start() -> () {
|
||||
|
||||
byte i=2
|
||||
float f
|
||||
word ww = $55aa
|
||||
byte i
|
||||
|
||||
set_carry()
|
||||
clear_carry()
|
||||
set_irqd()
|
||||
clear_irqd()
|
||||
|
||||
f=flt(i)
|
||||
i = msb(ww)
|
||||
i = lsb(ww)
|
||||
lsl(i)
|
||||
lsr(i)
|
||||
rol(i)
|
||||
ror(i)
|
||||
rol2(i)
|
||||
ror2(i)
|
||||
float yy
|
||||
word pixely
|
||||
word yoffset
|
||||
word height
|
||||
|
||||
|
||||
|
||||
while i<10 {
|
||||
_vm_write_num(i)
|
||||
_vm_write_char($8d)
|
||||
i++
|
||||
}
|
||||
|
||||
_vm_write_char($8d)
|
||||
|
||||
i=2
|
||||
repeat {
|
||||
_vm_write_num(i)
|
||||
_vm_write_char($8d)
|
||||
i++
|
||||
} until i>10
|
||||
; @todo expression must not result in float but in word
|
||||
yy = flt(height+1.1)
|
||||
pixely = height / 100
|
||||
;yy = height- 1.1
|
||||
;yy = height*1.1
|
||||
;yy = height/3.6
|
||||
;yy = height//3.6
|
||||
;yy = height**3.6
|
||||
;yy = height%3.6
|
||||
;yy = height/3.6+0.4
|
||||
;yy = 2/height/3.6+0.4
|
||||
;yy = (pixely-yoffset)/height/3.6+0.4
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -725,8 +725,7 @@ class BinaryExpression(var left: IExpression, val operator: String, var right: I
|
||||
val leftDt = left.resultingDatatype(namespace)
|
||||
val rightDt = right.resultingDatatype(namespace)
|
||||
return when(operator) {
|
||||
"+", "-", "*", "**", "%" -> 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 arithmeticOpDt(leftDt, rightDt)
|
||||
"//" -> if(leftDt==null || rightDt==null) null else integerDivisionOpDt(leftDt, rightDt)
|
||||
"&" -> leftDt
|
||||
"|" -> leftDt
|
||||
|
@ -722,7 +722,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
||||
if(sourceDatatype==DataType.WORD && targetDatatype==DataType.BYTE)
|
||||
checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position))
|
||||
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
|
||||
checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position))
|
||||
|
||||
|
@ -289,6 +289,15 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
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) {
|
||||
when(expr) {
|
||||
is RegisterExpr -> {
|
||||
@ -299,6 +308,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
translatePrefixOperator(expr.operator)
|
||||
}
|
||||
is BinaryExpression -> {
|
||||
checkForFloatPrecisionProblem(expr.left, expr.right)
|
||||
translate(expr.left)
|
||||
translate(expr.right)
|
||||
translateBinaryOperator(expr.operator)
|
||||
|
@ -7,7 +7,7 @@ import prog8.ast.Module
|
||||
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.
|
||||
* 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
|
||||
|
@ -1178,7 +1178,7 @@ class TestStackVmOpcodes {
|
||||
|
||||
@Test
|
||||
fun testReturn() {
|
||||
// @todo only tests return with zero return values
|
||||
// @todo this only tests return with zero return values for now.
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.RETURN),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
@ -1199,7 +1199,7 @@ class TestStackVmOpcodes {
|
||||
|
||||
@Test
|
||||
fun testCall() {
|
||||
// @todo only tests call with zero parameters
|
||||
// @todo this only tests call with zero parameters for now.
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.CALL, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "returned")),
|
||||
|
@ -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
|
||||
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
|
||||
to a smaller datatype.
|
||||
to a smaller datatype, or revert to integer arithmetic.
|
||||
|
||||
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.
|
||||
|
||||
.. 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
|
||||
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 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.
|
||||
For example, this means that if you divide two integer values (say: ``32500 / 99``) the result will be the integer floor
|
||||
|
||||
When a floating point value is used in a calculation, the result will be a floating point, and byte or word values
|
||||
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,
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user