Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.pascal.borland > #128 > unrolled thread

longint and/or overflow bug?

Started byJim Leonard <mobygamer@gmail.com>
First post2012-10-30 08:56 -0700
Last post2012-10-31 10:11 +0000
Articles 6 — 4 participants

Back to article view | Back to comp.lang.pascal.borland


Contents

  longint and/or overflow bug? Jim Leonard <mobygamer@gmail.com> - 2012-10-30 08:56 -0700
    Re: longint and/or overflow bug? Vinzent Höfler <0439279208b62c95f1880bf0f8776eeb@t-domaingrabbing.de> - 2012-10-30 18:18 +0100
      Re: longint and/or overflow bug? Jim Leonard <mobygamer@gmail.com> - 2012-10-30 12:31 -0700
        Re: longint and/or overflow bug? rugxulo@gmail.com - 2012-10-30 14:50 -0700
    Re: longint and/or overflow bug? Marco van de Voort <marcov@toad.stack.nl> - 2012-10-31 09:35 +0000
      Re: longint and/or overflow bug? Marco van de Voort <marcov@toad.stack.nl> - 2012-10-31 10:11 +0000

#128 — longint and/or overflow bug?

FromJim Leonard <mobygamer@gmail.com>
Date2012-10-30 08:56 -0700
Subjectlongint and/or overflow bug?
Message-ID<a3cac83f-4bb6-46ae-a9ab-70a7c0d73e5d@s18g2000yqh.googlegroups.com>
When I write and debug programs, it is always with range/stack/arith
checking on.  In my current project, I am seeing Arith overflow {$Q+}
errors when trying to do legal operations with a longint variable as
the destination.  Observe the following code:

===begin===
{$Q+,R+,S+}

const
  val1=$0123; val2=$4567;

var
  l:longint;
  w1,w2:word;

begin
  w1:=val1; w2:=val2;
  l:=w1 * w2; {Throws runtime 215 "arithmetic overflow" if $Q+}
  if l<>(val1*val2) then writeln('Error in longint math routines!');
end.
====end====

With $Q+, the second main line throws an overflow error even though
the source variables and values cannot possibly overflow the target.
With $Q-, the third line throws "error in longint math routines" as
the end result is wrong.

What is going on?  Is there a bug in the longint math routines, or a
bug in code generation, or something else?  If you run the above code
with your copy of TP7, do you see the same behavior?

(The workaround is to do everything "longhand" like this:

l:=w1;
l:=l * w2;

This works, but my code is starting to look ugly.)

[toc] | [next] | [standalone]


#129

FromVinzent Höfler <0439279208b62c95f1880bf0f8776eeb@t-domaingrabbing.de>
Date2012-10-30 18:18 +0100
Message-ID<almarsoft.4253489350356608845@news.individual.net>
In reply to#128
Jim Leonard <mobygamer@gmail.com> wrote:
>   l:=w1 * w2; {Throws runtime 215 "arithmetic overflow" if $Q+}

Yes. The value is calculated in word-range, so it does actually 
overflow. The type of the result variable does not matter at this 
point.

You must tell the compiler to calculate this as longint. I'm not sure 
if casting the whole expression to longint will suffice (probably 
not), but casting at least one operand should tell the compiler to 
use 32-bit arithmetic here.
Keep in mind that TP is a 16-bit compiler, it doesn't use 32-bit 
arithmetic by default.


Vinzent.

[toc] | [prev] | [next] | [standalone]


#130

FromJim Leonard <mobygamer@gmail.com>
Date2012-10-30 12:31 -0700
Message-ID<c17a1d09-2126-4b60-b9c3-a91e16eb503c@j10g2000yqc.googlegroups.com>
In reply to#129
On Oct 30, 12:18 pm, Vinzent Höfler
<0439279208b62c95f1880bf0f8776...@t-domaingrabbing.de> wrote:
> Jim Leonard <mobyga...@gmail.com> wrote:
> >   l:=w1 * w2; {Throws runtime 215 "arithmetic overflow" if $Q+}
>
> Keep in mind that TP is a 16-bit compiler, it doesn't use 32-bit
> arithmetic by default.

One would think that the compiler would be smart enough to output code
appropriate for the size of the  destination  -- I guess not!  I'm
quite surprised I haven't encountered this before, and I've been
writing programs with TP7 on and off for 20 years.

I quickly tested casting one of the operands to longint() and that
worked, thanks for the suggestion.

[toc] | [prev] | [next] | [standalone]


#131

Fromrugxulo@gmail.com
Date2012-10-30 14:50 -0700
Message-ID<2fa6513a-0cf9-4af6-8ecf-d2650aaa496f@googlegroups.com>
In reply to#130
Hi,

On Tuesday, October 30, 2012 2:31:07 PM UTC-5, Jim Leonard wrote:
> On Oct 30, 12:18 pm, Vinzent Höfler
> 
> <0439279208b62c95f1880bf0f8776...@t-domaingrabbing.de> wrote:
> 
> > Jim Leonard <mobyga...@gmail.com> wrote:
> 
> > >   l:=w1 * w2; {Throws runtime 215 "arithmetic overflow" if $Q+}

I only can test TP 5.5, and it doesn't seem to support $Q+ at all.
 
> > Keep in mind that TP is a 16-bit compiler, it doesn't use 32-bit arithmetic by default.
> 
> One would think that the compiler would be smart enough to output code
> appropriate for the size of the  destination  -- I guess not!  I'm
> quite surprised I haven't encountered this before, and I've been
> writing programs with TP7 on and off for 20 years.
> 
> I quickly tested casting one of the operands to
> longint() and that worked, thanks for the suggestion.

Yeah, for TP 5.5, it works fine if w1 and w2 are both defined as "longint" but not if they are "word".

Keep in mind that the compiler probably isn't aware that your "word"s are small enough to not overflow at multiply, which may or may not be a bug. Probably in the interest of efficiency, it decided to always do "word" arithmetic in word registers instead of always using slower "longint" calculations on the rare chance that it might overflow. I guess it can't (easily?) figure out what's best by heuristics. (Perhaps on overflow it should promote to larger type, if available, and try again.) Some languages just use bigint all the time for simplicity [REXX, Scheme?], but that's obviously less efficient than fixed size (native) register types.

I'm not totally sure what the Pascal standard(s) say about signed vs. unsigned numbers, overflow, etc. Though official Pascal doesn't even have "longint" (32-bit signed) nor "word" (16-bit unsigned) as distinct types.

And 16-bit does complicate things a bit when trying to support 32-bit numbers, as I've noticed in various 16-bit compilers. So there are sometimes restrictions on array indices, "for" variables, what built-ins (e.g. INC) will support, etc. Even "case" expression sometimes must be short. It honestly depends on the compiler! (I'm mainly thinking of the following 16-bit: ACK, FST, Oberon-M.)

Modula-2 was more complicated than "standard" Pascal due to CARDINAL, but that was added because of native machine support of it and due to 16-bitness of the original CPUs, so it was more useful for addressing on those old machines. Both Modula-3 and Oberon simplified type compatibility a bit but in different ways. Modula-3 just made CARDINAL the positive subset of INTEGER; Oberon removed CARDINAL completely (as Ceres was 32-bit) but did have LONGINT and SHORTINT. Yet even that can cause complication and confusion in some obscure cases, so Wirth went ahead and removed them entirely from Oberon-07.

In short, it's hard to make an easy-to-use type system that works for 16-bit, 32-bit, 64-bit, etc. Sadly, most languages and implementations seem to assume too many things these days, esp. 32-bit or 64-bit or POSIX or Windows with Unicode and multi-threading, so it makes portability that much harder unless you go the easy (obvious) route of just using whatever's popular (i.e. not DOS).

[toc] | [prev] | [next] | [standalone]


#132

FromMarco van de Voort <marcov@toad.stack.nl>
Date2012-10-31 09:35 +0000
Message-ID<slrnk91s66.1ddn.marcov@toad.stack.nl>
In reply to#128
On 2012-10-30, Jim Leonard <mobygamer@gmail.com> wrote:
>
> var
>   l:longint;
>   w1,w2:word;
>
> begin
>   w1:=val1; w2:=val2;
>   l:=w1 * w2; {Throws runtime 215 "arithmetic overflow" if $Q+}

typing:
longint :=word * word

Pascal rule is afaik that an expression is evaluated in (at least?) the
combined range of the operands.  Which is word.

So the above translates to

tempresult: word = word * word
longint:=convert(word,longint,tempresult);

Note that FPC/Delphi do the same with 64-bit results (in 32-bit mode).

[toc] | [prev] | [next] | [standalone]


#133

FromMarco van de Voort <marcov@toad.stack.nl>
Date2012-10-31 10:11 +0000
Message-ID<slrnk91ub5.1j6f.marcov@toad.stack.nl>
In reply to#132
On 2012-10-31, Marco van de Voort <marcov@toad.stack.nl> wrote:
> On 2012-10-30, Jim Leonard <mobygamer@gmail.com> wrote:
>>
>> var
>>   l:longint;
>>   w1,w2:word;
>>
>> begin
>>   w1:=val1; w2:=val2;
>>   l:=w1 * w2; {Throws runtime 215 "arithmetic overflow" if $Q+}
>
> typing:
> longint :=word * word

> Pascal rule is afaik that an expression is evaluated in (at least?) the
> combined range of the operands.  Which is word.

Hmm, thinking of it, in Pascal the above is impossible, since range(word)
is not a subset of range(integer). Those are special yet again.

Still the behaviour is normal and consistent in the Borland lines and
compatibles.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.pascal.borland


csiph-web