user1548072
user1548072

Reputation: 477

Pascal set acts weirdly

I don't understand why this code doesn't work properly:

program selection;
var 
    n : integer;
begin
    readln(n);
    if (n in [100..1000]) then writeln('Selected!');
    readln;
end.

this works fine for me with values between 1 and 233, if I enter 233, or more, the writeln.. doesn't get executed. This is very strange. I've also tried with other values, and the result is more or less the same, with only difference being the value it fails on.

Upvotes: 3

Views: 317

Answers (2)

David Heffernan
David Heffernan

Reputation: 612993

Rob has explained why you cannot use Delphi sets for what you need. I would also stress that a set is a very heavyweight type to store what amounts to an interval. Once this is recognised, it makes sense to use a function like InRange which operates on intervals.

As a fun exercise, you can write a simple record that represents an interval. And then you can use operator overloading to implement an in operator that will test for interval inclusion. This allows you to use the readable notation, and have the natural storage for an interval. And of course there are no constrains on element size.

Here is the simple demonstration:

{$APPTYPE CONSOLE}

type
  TInterval = record
  public
    Low: Integer;
    High: Integer;
  public
    class operator In(const Value: Integer; 
      const Interval: TInterval): Boolean; inline;
  end;

class operator TInterval.In(const Value: Integer; 
   const Interval: TInterval): Boolean;
begin
  Result := (Value>=Interval.Low) and (Value<=Interval.High);
  // or implement with a call to Math.InRange()
end;

function Interval(Low, High: Integer): TInterval; inline;
begin
  Result.Low := Low;
  Result.High := High;
end;

begin
  Writeln(25 in Interval(10, 100));
  Writeln(125 in Interval(10, 100));
  Writeln(2500 in Interval(1000, 10000));
  Writeln(12500 in Interval(1000, 10000));
  Readln;
end.

Upvotes: 7

Rob Kennedy
Rob Kennedy

Reputation: 163287

Delphi sets only go up to 255; a set with a maximum value of 1000 doesn't work. I'm a little surprised your code compiled.

When truncated to 8 bits, the value 1000 is 232, which explains why values larger than that fail.

Instead, you can use the InRange function; it uses closed ranges just like set constructors.

if InRange(n, 100, 1000) then ...

You can also use plain old inequality operators to test whether the value lies in the given range:

if (100 <= n) and (n <= 1000) then ...

Finally, you can use a case statement. Case-statement selectors aren't sets, so they're not subject to the same rules as sets.

case n of
  100..1000: begin ... end;
end;

The downside is that it looks a little clumsy when there's only one case branch.

Upvotes: 13

Related Questions