mirror of
https://github.com/irmen/prog8.git
synced 2024-12-01 15:52:54 +00:00
changed float handling and appropriate compiler messages
This commit is contained in:
parent
d990b05998
commit
53cd50ad48
@ -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
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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")),
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user