View Issue Details

IDProjectCategoryView StatusLast Update
0033963FPCCompilerpublic2019-12-01 21:30
ReporterLeslieAssigned ToFlorian Klämpfl 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.2.0Product Build 
Target VersionFixed in Version3.3.1 
Summary0033963: Wrong result when a currency variable is multiplied by a constant
Descriptionvar C: Currency;
begin
  c:= 1000;
  c:= c*1.05;
  // at this point C=1000 instead of 1050
end;
Additional InformationIt's been like this for months.
TagsNo tags attached.
Fixed in Revision43620, 43621
FPCOldBugId
FPCTarget-
Attached Files
  • 0033963_currency_mult.patch (2,949 bytes)
    diff --git a/compiler/nadd.pas b/compiler/nadd.pas
    index 948ff4ae45..f68181f606 100644
    --- a/compiler/nadd.pas
    +++ b/compiler/nadd.pas
    @@ -2361,14 +2361,14 @@ implementation
     {$ifndef VER3_0}
                           { if left is a currency integer constant, we can get rid of the factor 10000 }
                           { int64(...) causes a cast on currency, so it is the currency value multiplied by 10000 }
    -                      if (left.nodetype=realconstn) and (is_currency(left.resultdef)) and ((int64(trealconstnode(left).value_currency) mod 10000)=0) then
    +                      if (left.nodetype=realconstn) and (is_currency(left.resultdef)) and ((int64(trealconstnode(left).value_currency) mod 100000000)=0) then
                             begin
                               { trealconstnode expects that value_real and value_currency contain valid values }
                               trealconstnode(left).value_currency:=trealconstnode(left).value_currency {$ifdef FPC_CURRENCY_IS_INT64}div{$else}/{$endif} 10000;
                               trealconstnode(left).value_real:=trealconstnode(left).value_real/10000;
                             end
                           { or if right is an integer constant, we can get rid of its factor 10000 }
    -                      else if (right.nodetype=realconstn) and (is_currency(right.resultdef)) and ((int64(trealconstnode(right).value_currency) mod 10000)=0) then
    +                      else if (right.nodetype=realconstn) and (is_currency(right.resultdef)) and ((int64(trealconstnode(right).value_currency) mod 100000000)=0) then
                             begin
                               { trealconstnode expects that value and value_currency contain valid values }
                               trealconstnode(right).value_currency:=trealconstnode(right).value_currency {$ifdef FPC_CURRENCY_IS_INT64}div{$else}/{$endif} 10000;
    @@ -2385,10 +2385,10 @@ implementation
                         begin
     {$ifndef VER3_0}
                           { if left is a currency integer constant, we can get rid of the factor 10000 }
    -                      if (left.nodetype=ordconstn) and (is_currency(left.resultdef)) and ((tordconstnode(left).value mod 10000)=0) then
    +                      if (left.nodetype=ordconstn) and (is_currency(left.resultdef)) and ((tordconstnode(left).value mod 100000000)=0) then
                             tordconstnode(left).value:=tordconstnode(left).value div 10000
                           { or if right is an integer constant, we can get rid of its factor 10000 }
    -                      else if (right.nodetype=ordconstn) and (is_currency(right.resultdef)) and ((tordconstnode(right).value mod 10000)=0) then
    +                      else if (right.nodetype=ordconstn) and (is_currency(right.resultdef)) and ((tordconstnode(right).value mod 100000000)=0) then
                             tordconstnode(right).value:=tordconstnode(right).value div 10000
                           else
     {$endif VER3_0}
    
  • tcurrency.pas (2,601 bytes)
    program tcurrency;
    
    { test basic mathematical operations (+,-,*,/) using currency data type }
    
    var
      c1, c2: Currency;
      d: Double;
      i: Integer;
      i64: int64;
    
    begin
      writeln('Currency and Double ...');
      // addition double
      d := 1;
      c1 := 2;
      c2 := 3;
      if c1+d <> c2 then begin
        writeln('Invalid currency+double=', c1+d, ', but expected ', c2);
        halt(1);
      end;
      // subtraction double
      d := 3;
      c1 := 2;
      c2 := -1;
      if c1-d <> c2 then begin
        writeln('Invalid currency-double=', c1-d, ', but expected ', c2);
        halt(1);
      end;
      // multiplication double
      d := -100;
      c1 := 12.34;
      c2 := -1234;
      if d*c1 <> c2 then begin
        writeln('Invalid currency*double=', d*c1, ', but expected ', c2);
        halt(1);
      end;
      // division double
      d := 100;
      c1 := 12.34;
      c2 := 0.1234;
      if c1/d <> c2 then begin
        writeln('Invalid currency/double=', c1/d, ', but expected ', c2);
        halt(1);
      end;
    
      writeln('Currency and Integer ...');
      // addition integer
      i := 1;
      c1 := 2;
      c2 := 3;
      if c1+i <> c2 then begin
        writeln('Invalid currency+integer=', c1+i, ', but expected ', c2);
        halt(2);
      end;
      // subtraction integer
      i := 10;
      c1 := -2;
      c2 := -12;
      if c1-i <> c2 then begin
        writeln('Invalid currency-integer=', c1-i, ', but expected ', c2);
        halt(2);
      end;
      // multiplication integer
      i := 100;
      c1 := 12.34;
      c2 := 1234;
      if i*c1 <> c2 then begin
        writeln('Invalid currency*integer=', i*c1, ', but expected ', c2);
        halt(2);
      end;
      // division integer
      i := 1000;
      c1 := 123.4;
      c2 := 0.1234;
      if c1/i <> c2 then begin
        writeln('Invalid currency/integer=', c1/i, ', but expected ', c2);
        halt(2);
      end;
    
      writeln('Currency and Int64 ...');
      // addition int64
      i64 := 1;
      c1 := 12.3456;
      c2 := 13.3456;
      if c1+i64 <> c2 then begin
        writeln('Invalid currency+int64=', c1+i64, ', but expected ', c2);
        halt(3);
      end;
      // subtraction int64
      i64 := 100;
      c1 := 12.3456;
      c2 := -87.6544;
      if c1-i64 <> c2 then begin
        writeln('Invalid currency-int64=', c1-i64, ', but expected ', c2);
        halt(3);
      end;
      // multiplication int64
      i64 := -10000;
      c1 := 12.3456;
      c2 := -123456;
      if i64*c1 <> c2 then begin
        writeln('Invalid currency*int64=', i64*c1, ', but expected ', c2);
        halt(3);
      end;
      // division int64
      i64 := -10000;
      c1 := 123456;
      c2 := -12.3456;
      if c1/i64 <> c2 then begin
        writeln('Invalid currency/int64=', c1/i64, ', but expected ', c2);
        halt(3);
      end;
    end.
    
    tcurrency.pas (2,601 bytes)
  • project1.zip (1,202 bytes)
  • project1.s-linux-i386.zip (3,384 bytes)
  • project1.s-win32-i386.zip (3,014 bytes)
  • project1.s-linux-x86_64.zip (3,538 bytes)
  • project1.s-win64-x86_64.zip (3,197 bytes)

Relationships

related to 0036176 assignedFlorian Currency multiply by constant (divisible by 10000) on Win64 

Activities

Thaddy de Koning

2018-07-11 19:20

reporter   ~0109369

Oh? what's this then?
{$ifdef fpc}{$mode delphi}{$H+}{$endif}
var C: Currency;
begin
  c:= 1000;
  c:= c*1.05;
  // at this point C=1050
  writeln(c:4:2);
end.

------------------output--------------
1050.00


------------------
(program exited with code: 0)
Press return to continue
------------------

Thaddy de Koning

2018-07-11 19:48

reporter   ~0109371

Last edited: 2018-07-11 19:49

View 2 revisions

Meaning I did not see OS nor platform. The above is 32 bit armhf raspbian.

Martok

2018-07-11 20:17

reporter   ~0109372

This is platform issue. Currency on x64 is parsed with integers, that works. On x86, it is a true real value, where a loss of precision causes the "1.05" to be stored as "1" instead of the correct "10500".

I'll check it out, was digging around in that part of the compiler anyway.

José Mejuto

2018-07-11 20:55

reporter   ~0109373

@Martok: Currency should be int64 on all platforms, at least 32 and 64 bits. Maybe you are confused with Comp ?

Martok

2018-07-11 21:50

reporter   ~0109377

Currency is integer arithmetics executed on the 80bit-FPU for x86 (plenty of precision there). It is pure int64 with "normal" instructions on x64. I think that should be alright.

c+1.05 works, c*1.05 looses the 1e4 factor at some point.

Martok

2018-07-11 23:22

reporter  

0033963_currency_mult.patch (2,949 bytes)
diff --git a/compiler/nadd.pas b/compiler/nadd.pas
index 948ff4ae45..f68181f606 100644
--- a/compiler/nadd.pas
+++ b/compiler/nadd.pas
@@ -2361,14 +2361,14 @@ implementation
 {$ifndef VER3_0}
                       { if left is a currency integer constant, we can get rid of the factor 10000 }
                       { int64(...) causes a cast on currency, so it is the currency value multiplied by 10000 }
-                      if (left.nodetype=realconstn) and (is_currency(left.resultdef)) and ((int64(trealconstnode(left).value_currency) mod 10000)=0) then
+                      if (left.nodetype=realconstn) and (is_currency(left.resultdef)) and ((int64(trealconstnode(left).value_currency) mod 100000000)=0) then
                         begin
                           { trealconstnode expects that value_real and value_currency contain valid values }
                           trealconstnode(left).value_currency:=trealconstnode(left).value_currency {$ifdef FPC_CURRENCY_IS_INT64}div{$else}/{$endif} 10000;
                           trealconstnode(left).value_real:=trealconstnode(left).value_real/10000;
                         end
                       { or if right is an integer constant, we can get rid of its factor 10000 }
-                      else if (right.nodetype=realconstn) and (is_currency(right.resultdef)) and ((int64(trealconstnode(right).value_currency) mod 10000)=0) then
+                      else if (right.nodetype=realconstn) and (is_currency(right.resultdef)) and ((int64(trealconstnode(right).value_currency) mod 100000000)=0) then
                         begin
                           { trealconstnode expects that value and value_currency contain valid values }
                           trealconstnode(right).value_currency:=trealconstnode(right).value_currency {$ifdef FPC_CURRENCY_IS_INT64}div{$else}/{$endif} 10000;
@@ -2385,10 +2385,10 @@ implementation
                     begin
 {$ifndef VER3_0}
                       { if left is a currency integer constant, we can get rid of the factor 10000 }
-                      if (left.nodetype=ordconstn) and (is_currency(left.resultdef)) and ((tordconstnode(left).value mod 10000)=0) then
+                      if (left.nodetype=ordconstn) and (is_currency(left.resultdef)) and ((tordconstnode(left).value mod 100000000)=0) then
                         tordconstnode(left).value:=tordconstnode(left).value div 10000
                       { or if right is an integer constant, we can get rid of its factor 10000 }
-                      else if (right.nodetype=ordconstn) and (is_currency(right.resultdef)) and ((tordconstnode(right).value mod 10000)=0) then
+                      else if (right.nodetype=ordconstn) and (is_currency(right.resultdef)) and ((tordconstnode(right).value mod 100000000)=0) then
                         tordconstnode(right).value:=tordconstnode(right).value div 10000
                       else
 {$endif VER3_0}

Marco van de Voort

2018-07-11 23:30

manager   ~0109381

# [4] c:= 1000;
    vmovsd _$PROGRAM$_Ld1,%xmm0
    vmovsd %xmm0,U_$P$PROGRAM_$$_C
# [5] c:= c*1.05;
    fildq U_$P$PROGRAM_$$_C
    fildq _$PROGRAM$_Ld2
    fmulp %st,%st(1)
    fistpq U_$P$PROGRAM_$$_C

globl _$PROGRAM$_Ld1
_$PROGRAM$_Ld1:
# value: 0d+1.00000000000000000000E+0007
    .byte 128,150,152,0,0,0,0,0

.section .rodata.n__$PROGRAM$_Ld2,"d"
    .balign 8
.globl _$PROGRAM$_Ld2
_$PROGRAM$_Ld2:
# value: 0d+1.00000000000000000000E+0000
    .byte 1,0,0,0,0,0,0,0

Marco van de Voort

2018-07-11 23:30

manager   ~0109382

Seems ld2 simply isn't 1.05

Martok

2018-07-11 23:34

reporter   ~0109383

Last edited: 2018-07-12 09:33

View 2 revisions

Found it. The problem comes from the fix to 0033439 in r38555.

int64(value_currency) returns the scaled integer value. However, since at that point the value_real has already been explicitly scaled in the the Real to Currency type conversion, (int64(value_currency) mod 10000) is always true, so the divisio always happens and any decimals get cut off.

Proposed patch is attached, the 10000² looks a bit weird, but it does what it should. The test for 0033439 still passes.

J. Gareth Moreton

2018-07-12 13:22

developer   ~0109406

Maybe I'm being a bit pedantic here, but shouldn't the Currency data type be treated as an integer internally rather than as a floating-point number? It is, after all, just a signed 64-bit integer whose decimal representation is split into (v div 10000).(v mod 10000), and would be faster as well instead of relying on XMM0 registers and the outdated floating-point stack.

For Currency * Currency operations, the division by 10000² can be translated into a multiplication by a particular constant and taking the high-order QWord of the result.

Martok

2018-07-12 14:31

reporter   ~0109410

Currency is always treated as an integer for comparisions (in fact, this is the only place that ever reads value_currency - so it may not really be needed at all, see below).

It never uses the xmm registers. On x86_64, s64currencytype.typ=orddef and uses the general-purpose registers.

On x86, s64currencytype.typ=floatdef and arithmetics uses the FPU. This is actually faster than emulated int64 operations, and not a precision issue because the 80-bit extended type in fact has a 64bit mantissa, so it can represent any int64 value accurately.

All of that is Delphi compatible.

(Currency*Currency is just a division by 10000, btw: one of them remains for storage after the operation.)

Thaddy de Koning

2018-07-12 16:41

reporter   ~0109412

Currency should and is defined as an internal integer type that scales to a real for output. (any real)
So code that uses the FPU is banned, unless using integer only operations.

J. Gareth Moreton

2018-07-12 17:16

developer   ~0109414

Ah, okay. Thanks Martok. I can see it faster on i386 because of the lack of native 32-bit. It just seemed a bit confusing because the assembly language listed above utilised both XMM and the floating-point stack (and producing the wrong result).

Martok

2018-07-12 19:59

reporter   ~0109416

I had one more look, the "vmovsd, %xmm" in Marco's disassembly isn't there for me, and that's because it is an optimized QWORD mov that FPC generates on -CpCOREAVX:

....\project1.lpr:5 c:= 1000;
00401569 a108c04000 mov 0x40c008,%eax
0040156E a310d04000 mov %eax,0x40d010
00401573 a10cc04000 mov 0x40c00c,%eax
00401578 a314d04000 mov %eax,0x40d014
....\project1.lpr:6 c:= c*1.05;
0040157D df2d10d04000 fildll 0x40d010
00401583 df2d10c04000 fildll 0x40c010
00401589 dec9 fmulp %st,%st(1)
0040158B df3d10d04000 fistpll 0x40d010

....\project1.lpr:5 c:= 1000;
00401569 c5fb100508c04000 vmovsd 0x40c008,%xmm0
00401571 c5fb110510d04000 vmovsd %xmm0,0x40d010
....\project1.lpr:6 c:= c*1.05;
00401579 df2d10d04000 fildll 0x40d010
0040157F df2d10c04000 fildll 0x40c010
00401585 dec9 fmulp %st,%st(1)
00401587 df3d10d04000 fistpll 0x40d010

Leslie

2018-07-13 21:17

reporter   ~0109435

Forgot to include that the target is Win32.

J. Gareth Moreton

2018-07-14 01:03

developer   ~0109439

It seems slightly weird because I would have thought that the 32-bit versions would be more efficient using something like:

movl $10000000, 0x40d010 ; 100 * 10000
movl $0, 0x40d014

Even a 64-bit version using movq can accept "movq imm32, mem64", so long as the constant falls within the range of a signed 32-bit integer.

Leslie

2018-07-18 15:51

reporter   ~0109558

Last edited: 2018-07-19 21:36

View 2 revisions

Does Martok's suggestion solve the problem?

Leslie

2018-07-25 23:32

reporter   ~0109677

Is anyone working on this?

LacaK

2018-07-27 07:15

developer   ~0109700

Can we add compact test unit for currency data type, as there was recently more bugs involved currency. As an example I have attached sample ...

LacaK

2018-07-27 07:16

developer  

tcurrency.pas (2,601 bytes)
program tcurrency;

{ test basic mathematical operations (+,-,*,/) using currency data type }

var
  c1, c2: Currency;
  d: Double;
  i: Integer;
  i64: int64;

begin
  writeln('Currency and Double ...');
  // addition double
  d := 1;
  c1 := 2;
  c2 := 3;
  if c1+d <> c2 then begin
    writeln('Invalid currency+double=', c1+d, ', but expected ', c2);
    halt(1);
  end;
  // subtraction double
  d := 3;
  c1 := 2;
  c2 := -1;
  if c1-d <> c2 then begin
    writeln('Invalid currency-double=', c1-d, ', but expected ', c2);
    halt(1);
  end;
  // multiplication double
  d := -100;
  c1 := 12.34;
  c2 := -1234;
  if d*c1 <> c2 then begin
    writeln('Invalid currency*double=', d*c1, ', but expected ', c2);
    halt(1);
  end;
  // division double
  d := 100;
  c1 := 12.34;
  c2 := 0.1234;
  if c1/d <> c2 then begin
    writeln('Invalid currency/double=', c1/d, ', but expected ', c2);
    halt(1);
  end;

  writeln('Currency and Integer ...');
  // addition integer
  i := 1;
  c1 := 2;
  c2 := 3;
  if c1+i <> c2 then begin
    writeln('Invalid currency+integer=', c1+i, ', but expected ', c2);
    halt(2);
  end;
  // subtraction integer
  i := 10;
  c1 := -2;
  c2 := -12;
  if c1-i <> c2 then begin
    writeln('Invalid currency-integer=', c1-i, ', but expected ', c2);
    halt(2);
  end;
  // multiplication integer
  i := 100;
  c1 := 12.34;
  c2 := 1234;
  if i*c1 <> c2 then begin
    writeln('Invalid currency*integer=', i*c1, ', but expected ', c2);
    halt(2);
  end;
  // division integer
  i := 1000;
  c1 := 123.4;
  c2 := 0.1234;
  if c1/i <> c2 then begin
    writeln('Invalid currency/integer=', c1/i, ', but expected ', c2);
    halt(2);
  end;

  writeln('Currency and Int64 ...');
  // addition int64
  i64 := 1;
  c1 := 12.3456;
  c2 := 13.3456;
  if c1+i64 <> c2 then begin
    writeln('Invalid currency+int64=', c1+i64, ', but expected ', c2);
    halt(3);
  end;
  // subtraction int64
  i64 := 100;
  c1 := 12.3456;
  c2 := -87.6544;
  if c1-i64 <> c2 then begin
    writeln('Invalid currency-int64=', c1-i64, ', but expected ', c2);
    halt(3);
  end;
  // multiplication int64
  i64 := -10000;
  c1 := 12.3456;
  c2 := -123456;
  if i64*c1 <> c2 then begin
    writeln('Invalid currency*int64=', i64*c1, ', but expected ', c2);
    halt(3);
  end;
  // division int64
  i64 := -10000;
  c1 := 123456;
  c2 := -12.3456;
  if c1/i64 <> c2 then begin
    writeln('Invalid currency/int64=', c1/i64, ', but expected ', c2);
    halt(3);
  end;
end.
tcurrency.pas (2,601 bytes)

Leslie

2018-08-02 07:33

reporter   ~0109823

Unit test sounds like a good idea.

Leslie

2018-08-18 14:24

reporter   ~0110122

I left severity as minor when creating the ticket, but this error can cause very-very significant problems (which may remain unnoticed for a long time) for any app dealing with currency.

Leslie

2018-09-06 11:14

reporter   ~0110532

In the current trunk the problem still remains.

I believe this is a serious issue worth attention.

Leslie

2018-09-06 11:22

reporter   ~0110533

Further more:

OS: win64, CPU: x86_64

The problem is the same.

Michael Van Canneyt

2018-09-08 12:20

administrator   ~0110557

I can reproduce the bug on linux 64-bit.

Serge Anvarov

2018-09-09 02:28

reporter   ~0110573

Sorry, maybe something I missed, but in Windows I have displays 1050.00. At least so: FPC 3.04 х64, FPC 3.04 х32, FPC 3.11 х64. Intel CPU.

Martok

2018-09-14 20:00

reporter   ~0110751

@Serge: this is a regression, it was okay before r38555.

Leslie

2018-09-17 21:34

reporter   ~0110835

Until this is fixed would it be possible to revert to the previously working implementation?

Leslie

2018-09-29 19:12

reporter   ~0111085

It would really make sense to revert until this can be properly fixed.

Leslie

2018-10-11 09:26

reporter   ~0111361

This bug can cost serious money for anyone not knowing about it. I really do not understand the lack of activity here.

Michael Van Canneyt

2018-10-11 09:56

administrator   ~0111363

1. Trunk can and will contain bugs, that's what it is for.
   Use a released version of FPC if you don't want to have that.
   

2. Who says there is no activity ?
   It is not because there is no reporting here that there is no work being done.

3. 'It can cost serious money' is not an argument for an open source project.

Cyrax

2018-10-11 10:33

reporter  

project1.zip (1,202 bytes)

Cyrax

2018-10-11 10:46

reporter   ~0111367

Last edited: 2018-10-11 10:59

View 2 revisions

Attached test project for this bug.

The project outputs following info when run:
linux-i386 : 
  C :  1.000000000000000000E+03 // C := 1000
  C :  1.000000000000000000E+03 // C := C * 1.05;
linux-x86_64:
  C :  1.000000000000000000E+03 // C := 1000
  C :  1.000000000000000000E+03 // C := C * 1.05;
win32-i386:
  C :  1.000000000000000000E+03 // C := 1000
  C :  1.000000000000000000E+03 // C := C * 1.05;
win64-x86_64:
  C :  1.000000000000000000E+03 // C := 1000
  C :  1.050000000000000000E+03 // C := C * 1.05;

  
---

FPC trunk 3.3.1-r39899.

FPC trunk was built with these make commands :
i386 : make clean all install OPT=-gw2 -godwarfsets -godwarfmethodclassprefix -gl -O- -Xs- -Si- -vbq -Sew- -dEXTDEBUG -Xd -Fl/usr/lib32 -dTEST_WIN32_SEH FPC=fpc REVSTR=39899 IDE=1 NOWPOCYCLE=1 INSTALL_PREFIX=/mnt/UUSI_OHJELMOINTI/ohjelmointi/pascal/binaries/fpc/i386/trunk/3.3.1/binary/trunk
x86_64 : make clean all install OPT=-gw2 -godwarfsets -godwarfmethodclassprefix -gl -O- -Xs- -Si- -vbq -Sew- -dEXTDEBUG   FPC=fpc REVSTR=39899 IDE=1 NOWPOCYCLE=1 INSTALL_PREFIX=/mnt/UUSI_OHJELMOINTI/ohjelmointi/pascal/binaries/fpc/x86_64/trunk/3.3.1/binary/trunk


FPC cross compilers for targeting Windows platforms was built with same options.

Cyrax

2018-10-11 10:51

reporter  

project1.s-linux-i386.zip (3,384 bytes)

Cyrax

2018-10-11 10:52

reporter  

project1.s-win32-i386.zip (3,014 bytes)

Cyrax

2018-10-11 10:54

reporter  

project1.s-linux-x86_64.zip (3,538 bytes)

Cyrax

2018-10-11 10:56

reporter  

project1.s-win64-x86_64.zip (3,197 bytes)

Thaddy de Koning

2018-10-11 13:17

reporter   ~0111370

the project outputs
C : 1.000000000000000000E+03
C : 1.050000000000000000E+03
On armhf-linux r39909 (and before)

Florian

2018-10-11 20:41

administrator   ~0111381

I am working on it, but I found out that some parts of the currency support need rework. As the changed are not ready yet and in my private git mirror, you see no activity.

And as Michael said: this is no release version.

Ondrej Pokorny

2019-02-21 20:40

developer   ~0114340

> 1. Trunk can and will contain bugs, that's what it is for.
> Use a released version of FPC if you don't want to have that.

Yes, but on the other hand if you want to have testers and external contributors you need people who actually use trunk.

I can understand that sometimes trunk is broken but it shouldn't be broken a long time. Especially in crucial parts like the compiler.

Issue History

Date Modified Username Field Change
2018-07-10 23:59 Leslie New Issue
2018-07-11 19:20 Thaddy de Koning Note Added: 0109369
2018-07-11 19:48 Thaddy de Koning Note Added: 0109371
2018-07-11 19:49 Thaddy de Koning Note Edited: 0109371 View Revisions
2018-07-11 20:17 Martok Note Added: 0109372
2018-07-11 20:55 José Mejuto Note Added: 0109373
2018-07-11 21:50 Martok Note Added: 0109377
2018-07-11 23:22 Martok File Added: 0033963_currency_mult.patch
2018-07-11 23:30 Marco van de Voort Note Added: 0109381
2018-07-11 23:30 Marco van de Voort Note Added: 0109382
2018-07-11 23:34 Martok Note Added: 0109383
2018-07-12 09:33 Martok Note Edited: 0109383 View Revisions
2018-07-12 13:22 J. Gareth Moreton Note Added: 0109406
2018-07-12 14:31 Martok Note Added: 0109410
2018-07-12 16:41 Thaddy de Koning Note Added: 0109412
2018-07-12 17:16 J. Gareth Moreton Note Added: 0109414
2018-07-12 19:59 Martok Note Added: 0109416
2018-07-13 21:17 Leslie Note Added: 0109435
2018-07-14 01:03 J. Gareth Moreton Note Added: 0109439
2018-07-18 15:51 Leslie Note Added: 0109558
2018-07-19 21:36 Leslie Note Edited: 0109558 View Revisions
2018-07-25 23:32 Leslie Note Added: 0109677
2018-07-27 07:15 LacaK Note Added: 0109700
2018-07-27 07:16 LacaK File Added: tcurrency.pas
2018-08-02 07:33 Leslie Note Added: 0109823
2018-08-18 14:24 Leslie Note Added: 0110122
2018-09-06 11:14 Leslie Note Added: 0110532
2018-09-06 11:22 Leslie Note Added: 0110533
2018-09-08 12:20 Michael Van Canneyt Note Added: 0110557
2018-09-08 12:20 Michael Van Canneyt Assigned To => Michael Van Canneyt
2018-09-08 12:20 Michael Van Canneyt Status new => acknowledged
2018-09-08 23:01 Michael Van Canneyt Assigned To Michael Van Canneyt => Florian Klämpfl
2018-09-08 23:01 Michael Van Canneyt Status acknowledged => assigned
2018-09-09 02:28 Serge Anvarov Note Added: 0110573
2018-09-14 20:00 Martok Note Added: 0110751
2018-09-17 21:34 Leslie Note Added: 0110835
2018-09-29 19:12 Leslie Note Added: 0111085
2018-10-11 09:26 Leslie Note Added: 0111361
2018-10-11 09:56 Michael Van Canneyt Note Added: 0111363
2018-10-11 10:33 Cyrax File Added: project1.zip
2018-10-11 10:46 Cyrax Note Added: 0111367
2018-10-11 10:51 Cyrax File Added: project1.s-linux-i386.zip
2018-10-11 10:52 Cyrax File Added: project1.s-win32-i386.zip
2018-10-11 10:54 Cyrax File Added: project1.s-linux-x86_64.zip
2018-10-11 10:56 Cyrax File Added: project1.s-win64-x86_64.zip
2018-10-11 10:59 Cyrax Note Edited: 0111367 View Revisions
2018-10-11 13:17 Thaddy de Koning Note Added: 0111370
2018-10-11 20:41 Florian Note Added: 0111381
2019-02-21 20:40 Ondrej Pokorny Note Added: 0114340
2019-12-01 21:23 Florian Relationship added related to 0036176
2019-12-01 21:25 Florian Status assigned => resolved
2019-12-01 21:25 Florian Resolution open => fixed
2019-12-01 21:25 Florian Fixed in Version => 3.3.1
2019-12-01 21:25 Florian Fixed in Revision => 43620
2019-12-01 21:25 Florian FPCTarget => -
2019-12-01 21:30 Florian Product Version 3.1.1 => 3.2.0
2019-12-01 21:30 Florian Fixed in Revision 43620 => 43620, 43621