Ada : check if a result of division haven't decimal numbers - ada

I write my first ada program which include a condition that check if a value divide by a specific number haven't a decimal part :
EXEMPLE :
10 / 3 = 3.3333334 >> Wrong
12 / 2 = 6 >> Okay
45 / 5 = 9 >> Okay
...
But I can't find any function to do it...
this is my code :
with Ada.Text_IO, Ada.Integer_Text_IO ;
use Ada.Text_IO, Ada.Integer_Text_IO ;
procedure main is
...
testing : Natural := 0 ;
...
begin
...
if testing/i = ??? then -- if testing/i haven't decimal part --
...
end if ;
...
end main ;

This could work:
main.adb
with Ada.Text_IO;
procedure Main is
procedure Test_Remainder (X, Y : Integer) is
use Ada.Text_IO;
begin
-- Optional: add some test for Y being non-zero here...
Put (X'Image & " / " & Y'Image & " ==> ");
if (X rem Y = 0) then
Put_Line ("Okay");
else
Put_Line ("Wrong");
end if;
end Test_Remainder;
begin
Test_Remainder (10, 3);
Test_Remainder (12, 2);
Test_Remainder (45, 5);
end Main;
output
10 / 3 ==> Wrong
12 / 2 ==> Okay
45 / 5 ==> Okay
Note: For difference between mod and rem see e.g. Wikipedia.

Related

Is this a bug with UTF conversion in GNAT Ada

I am trying to convert from UTF 16 to UTF 8; this is a test program:
with Ada.Text_IO;
with Ada.Strings.UTF_Encoding.Conversions;
use Ada.Text_IO;
use Ada.Strings.Utf_Encoding.Conversions;
use Ada.Strings.UTF_Encoding;
procedure Main is
Str_8: UTF_8_String := "š¯„˛";
Str_16: UTF_16_Wide_String := Convert(Str_8);
Str_8_New: UTF_8_String := Convert(Str_16);
begin
if Str_8 = Str_8_New then
Put_Line("OK");
else
Put_Line("Bug");
end if;
end Main;
With latest GNAT community it prints "Bug". Is this a bug in the implementation of UTF conversion functions or am I doing something wrong here?
Edit: For reference, this issue has been accepted as Bug 95953 / Bug 95959.
As shown here, #DeeDee has identified a bug in the implementation of Convert for UTF_16 to UTF_8. The problem arises in byte three of the four byte value for code points in the range U+10000 to U+10FFFF, shown here. The source documents the relevant bit fields:
-- Codes in the range 16#10000# - 16#10FFFF#
-- UTF-16: 110110zzzzyyyyyy 110111yyxxxxxxxx
-- UTF-8: 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
-- Note: zzzzz in the output is input zzzz + 1
Byte three is constructed as follows:
Result (Len + 3) :=
Character'Val
(2#10_000000# or Shift_Left (yyyyyyyy and 2#1111#, 4)
or Shift_Right (xxxxxxxx, 6));
While the low four bits of yyyyyyyy are used to construct byte three, the value only needs to be shifted two places left to make room for the top two bits of xxxxxxxx. The correct formulation should be this:
Result (Len + 3) :=
Character'Val
(2#10_000000# or Shift_Left (yyyyyyyy and 2#1111#, 2)
or Shift_Right (xxxxxxxx, 6));
For reference, the complete example below recapitulates the original implementation, with enough additions to study the problem in isolation. The output shows the code point, the expected binary representation of the UTF-8 encoding, the conversion to UTF-16, the incorrect UTF-8 conversion, and the correct UTF-8 conversion.
Codepoint: 16#1D11E#
UTF-8: 4: 2#11110000# 2#10011101# 2#10000100# 2#10011110#
UTF-16: 2: 2#1101100000110100# 2#1101110100011110#
UTF-8: 4: 2#11110000# 2#10011101# 2#10010000# 2#10011110#
UTF-8: 4: 2#11110000# 2#10011101# 2#10000100# 2#10011110#
OK
Code:
-- https://stackoverflow.com/q/62564638/230513
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Strings.UTF_Encoding; use Ada.Strings.UTF_Encoding;
with Ada.Strings.UTF_Encoding.Conversions;
use Ada.Strings.UTF_Encoding.Conversions;
with Ada.Strings.UTF_Encoding.Wide_Wide_Strings;
use Ada.Strings.UTF_Encoding.Wide_Wide_Strings;
with Interfaces; use Interfaces;
with Unchecked_Conversion;
procedure UTFTest is
-- http://www.fileformat.info/info/unicode/char/1d11e/index.htm
Clef : constant Wide_Wide_String :=
(1 => Wide_Wide_Character'Val (16#1D11E#));
Str_8 : constant UTF_8_String := Encode (Clef);
Str_16 : constant UTF_16_Wide_String := Convert (Str_8);
Str_8_New : constant UTF_8_String := Convert (Str_16);
My_Str_8 : UTF_8_String := Convert (Str_16);
function To_Unsigned_16 is new Unchecked_Conversion (Wide_Character,
Interfaces.Unsigned_16);
procedure Raise_Encoding_Error (Index : Natural) is
Val : constant String := Index'Img;
begin
raise Encoding_Error
with "bad input at Item (" & Val (Val'First + 1 .. Val'Last) & ')';
end Raise_Encoding_Error;
function My_Convert (Item : UTF_16_Wide_String;
Output_BOM : Boolean := False) return UTF_8_String
is
Result : UTF_8_String (1 .. 3 * Item'Length + 3);
-- Worst case is 3 output codes for each input code + BOM space
Len : Natural;
-- Number of result codes stored
Iptr : Natural;
-- Pointer to next input character
C1, C2 : Unsigned_16;
zzzzz : Unsigned_16;
yyyyyyyy : Unsigned_16;
xxxxxxxx : Unsigned_16;
-- Components of double length case
begin
Iptr := Item'First;
-- Skip BOM at start of input
if Item'Length > 0 and then Item (Iptr) = BOM_16 (1) then
Iptr := Iptr + 1;
end if;
-- Generate output BOM if required
if Output_BOM then
Result (1 .. 3) := BOM_8;
Len := 3;
else
Len := 0;
end if;
-- Loop through input
while Iptr <= Item'Last loop
C1 := To_Unsigned_16 (Item (Iptr));
Iptr := Iptr + 1;
-- Codes in the range 16#0000# - 16#007F#
-- UTF-16: 000000000xxxxxxx
-- UTF-8: 0xxxxxxx
if C1 <= 16#007F# then
Result (Len + 1) := Character'Val (C1);
Len := Len + 1;
-- Codes in the range 16#80# - 16#7FF#
-- UTF-16: 00000yyyxxxxxxxx
-- UTF-8: 110yyyxx 10xxxxxx
elsif C1 <= 16#07FF# then
Result (Len + 1) :=
Character'Val (2#110_00000# or Shift_Right (C1, 6));
Result (Len + 2) :=
Character'Val (2#10_000000# or (C1 and 2#00_111111#));
Len := Len + 2;
-- Codes in the range 16#800# - 16#D7FF# or 16#E000# - 16#FFFF#
-- UTF-16: yyyyyyyyxxxxxxxx
-- UTF-8: 1110yyyy 10yyyyxx 10xxxxxx
elsif C1 <= 16#D7FF# or else C1 >= 16#E000# then
Result (Len + 1) :=
Character'Val (2#1110_0000# or Shift_Right (C1, 12));
Result (Len + 2) :=
Character'Val
(2#10_000000# or (Shift_Right (C1, 6) and 2#00_111111#));
Result (Len + 3) :=
Character'Val (2#10_000000# or (C1 and 2#00_111111#));
Len := Len + 3;
-- Codes in the range 16#10000# - 16#10FFFF#
-- UTF-16: 110110zzzzyyyyyy 110111yyxxxxxxxx
-- UTF-8: 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
-- Note: zzzzz in the output is input zzzz + 1
elsif C1 <= 2#110110_11_11111111# then
if Iptr > Item'Last then
Raise_Encoding_Error (Iptr - 1);
else
C2 := To_Unsigned_16 (Item (Iptr));
Iptr := Iptr + 1;
end if;
if (C2 and 2#111111_00_00000000#) /= 2#110111_00_00000000# then
Raise_Encoding_Error (Iptr - 1);
end if;
zzzzz := (Shift_Right (C1, 6) and 2#1111#) + 1;
yyyyyyyy :=
((Shift_Left (C1, 2) and 2#111111_00#) or
(Shift_Right (C2, 8) and 2#000000_11#));
xxxxxxxx := C2 and 2#11111111#;
Result (Len + 1) :=
Character'Val (2#11110_000# or (Shift_Right (zzzzz, 2)));
Result (Len + 2) :=
Character'Val
(2#10_000000# or Shift_Left (zzzzz and 2#11#, 4) or
Shift_Right (yyyyyyyy, 4));
Result (Len + 3) :=
Character'Val
(2#10_000000# or Shift_Left (yyyyyyyy and 2#1111#, 2) or
Shift_Right (xxxxxxxx, 6));
Result (Len + 4) :=
Character'Val (2#10_000000# or (xxxxxxxx and 2#00_111111#));
Len := Len + 4;
-- Error if input in 16#DC00# - 16#DFFF# (2nd surrogate with no 1st)
else
Raise_Encoding_Error (Iptr - 2);
end if;
end loop;
return Result (1 .. Len);
end My_Convert;
procedure Show (S : String) is
begin
Put(" UTF-8: ");
Put (S'Length, 1);
Put (":");
for C of S loop
Put (Character'Pos (C), 12, 2);
end loop;
New_Line;
end Show;
procedure Show (S : Wide_String) is
begin
Put("UTF-16: ");
Put (S'Length, 1);
Put (":");
for C of S loop
Put (Wide_Character'Pos (C), 20, 2);
end loop;
New_Line;
end Show;
begin
Put ("Codepoint:");
Put (Wide_Wide_Character'Pos (Clef (1)), 10, 16);
New_Line;
Show (Str_8);
Show (Str_16);
Show (Str_8_New);
My_Str_8 := My_Convert (Str_16);
Show (My_Str_8);
if Str_8 = My_Str_8 then
Put_Line ("OK");
else
Put_Line ("Bug");
end if;
end UTFTest;
See also Bug 95953 / Bug 95959.
There's a mismatch between the 3rd byte of Str_8 and Str_8_New which causes the round-trip to fail. This seems a bug.
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Strings.UTF_Encoding.Conversions;
use Ada.Strings.UTF_Encoding;
use Ada.Strings.UTF_Encoding.Conversions;
procedure Main is
-- UTF8 encoded Clef (U+1D11E)
-- (e.g.) https://unicode-table.com/en/1D11E/
Str_8 : constant UTF_8_String :=
Character'Val (16#F0#) &
Character'Val (16#9D#) &
Character'Val (16#84#) &
Character'Val (16#9E#);
Str_16 : constant UTF_16_Wide_String := Convert (Str_8);
Str_8_New : constant UTF_8_String := Convert (Str_16);
begin
for I in Str_8'Range loop
Put (Character'Pos (Str_8 (I)), 7, 16);
end loop;
New_Line (2);
for I in Str_16'Range loop
Put (Wide_Character'Pos (Str_16 (I)), 9, 16);
end loop;
New_Line (2);
for I in Str_8_New'Range loop
Put (Character'Pos (Str_8_New (I)), 7, 16);
end loop;
New_Line (2);
end Main;
output
$ ./main
16#F0# 16#9D# 16#84# 16#9E#
16#D834# 16#DD1E#
16#F0# 16#9D# 16#90# 16#9E#

Drawing a flag with diagonal crosses in a V-Shape (ADA)

I turn to Stackoverflow yet again. having gotten help here previously I hope to be received equally friendly once more. I have an assignment where I need to draw a flag (including a box-like shape around it and a V-shape of crosses in its midst) in ADA. Ive managed to make the box and roughly half of the crosses. can anyone clue me in as to how one easiest fills in the remainder of the crosses?
Its supposed to be a V-shape, like this:
+ +
+ +
+
etc
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure exercise2 is
subtype Cross_Rows is Integer range 2..80;
Rows : Cross_Rows;
Flag_Width : Cross_Rows;
Left : Positive;
Right : Positive;
procedure Row_Get (Rows: out Cross_Rows) is
begin
Put("Enter the number of cross rows (min is 3): ");
Get(Rows);
Skip_Line;
end Row_Get;
procedure Print_Top (Rows: in Cross_Rows) is
begin
Flag_Width := (Rows * 2) + 4;
Put("+");
for Col in 1..Flag_Width-3 loop
Put("-");
end loop;
Put("+");
New_Line;
end Print_Top;
procedure Print_Middle (Rows: in Cross_Rows) is
begin
Left := 1;
Right := Flag_Width - 5;
for R in 1..Rows loop
Put("! ");
for C in 1..Flag_Width - 4 loop
if C = Left or else C = Right then
Put("+");
else
Put(" ");
end if;
end loop;
Left := Left + 1;
Right := Right - 1;
Put_Line("!");
end loop;
end Print_Middle;
procedure Print_Bottom (Rows: in Cross_Rows) is
begin
Flag_Width := (Rows * 2) + 4;
Put("+");
for C in 1..Flag_Width-3 loop
Put("-");
end loop;
Put_Line("+");
end Print_Bottom;
begin
Row_Get(Rows);
Print_Top(Rows);
Print_Middle(Rows);
Print_Bottom(Rows);
end exercise2;
EDIT: Thanks to Jim Rogers I managed to edit my program to draw the flag. Unfortunately its not exactly the way its meant to be as the top crosses are supposed to touch the sides and not be spaced like they are now. Additionally the Main program and the subprograms arent allowed to be more than 15 lines each so I compartmentalized them.
The smallest flag is supposed to look like this. I'll try to work with his code to achieve this. But any help is of value! :)
n=1
+---+
!+ +!
! + !
+---+
n=2
+-----+
!+ +!
! + + !
! + !
+-----+
You need to keep track of the left and right columns for the '+' characters, increasing the left column position and decreasing the right column position with each iteration of your loop for printing the crosses.
The following program works for any number of rows of crosses from 3 to 80.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
subtype Cross_Rows is Integer range 3..80;
Rows : Cross_Rows;
Flag_Width : Cross_Rows;
Left : Positive;
Right : Positive;
begin
Put("Enter the number of cross rows (minimum is 3): ");
Get(Rows);
Skip_Line;
Flag_Width := (Rows * 2) + 4;
-- Print top row of flag boundary
for Col in 1..Flag_Width loop
Put("-");
end loop;
Put("-");
New_Line;
-- Print empty row below top flag boundary
Put("- ");
for C in 3..Flag_Width - 2 loop
Put(" ");
end loop;
Put_Line(" -");
-- Print crosses
Left := 1;
Right := Flag_Width - 5;
for R in 1..Rows loop
Put("- ");
for C in 1..Flag_Width - 4 loop
if C = Left or else C = Right then
Put("+");
else
Put(" ");
end if;
end loop;
Left := Left + 1;
Right := Right - 1;
Put_Line(" -");
end loop;
-- Print bottom flag rows
Put("- ");
for C in 3..Flag_Width - 2 loop
Put(" ");
end loop;
Put_Line(" -");
for C in 1..Flag_Width loop
Put("-");
end loop;
Put_Line("-");
end Main;
Example output is:
Enter the number of cross rows (minimum is 3): 7
-------------------
- -
- + + -
- + + -
- + + -
- + + -
- + + -
- + + -
- + -
- -
-------------------
Another approach uses the Set_Col procedure from Ada.Text_Io. Set_Col set the cursor to the specified column number in the current output line. For example, if the cursor starts at position 1 and you call Set_Col(10) the procedure will output 9 blank characters and set the column number to 10. You can then begin writing your non-blank output at column 10.
with Ada.Text_Io; use Ada.Text_IO;
with Ada.Integer_Text_Io; use Ada.Integer_Text_IO;
procedure V_columns is
subtype Cross_Rows is Integer range 3..80;
Rows : Cross_Rows;
Flag_Width : Positive;
Left : Positive;
Right : Positive;
begin
Put("Enter the number of cross rows (minimum is 3): ");
Get(Rows);
Skip_Line;
Flag_Width := (Rows * 2) + 4;
-- Print top row of flag boundary
for Col in 1..Flag_Width loop
Put("-");
end loop;
New_Line;
-- Print empty row below top flag boundary
Set_Col(1);
Put("|");
Set_Col(Positive_Count(Flag_Width));
Put_Line("|");
-- Print crosses
Left := 3;
Right := Flag_Width - 3;
for R in 1..Rows loop
Set_Col(1);
Put("|");
if Left < Right then
Set_Col(Positive_Count(Left));
Put("+");
Set_Col(Positive_Count(Right));
Put("+");
else
Set_Col(Positive_Count(Right));
Put("+");
end if;
Set_Col(Positive_Count(Flag_Width));
Put("|");
New_Line;
Left := Left + 1;
Right := Right - 1;
end loop;
-- Print bottom flag rows
Set_Col(1);
Put("|");
Set_Col(Positive_Count(Flag_Width));
Put_Line("|");
for C in 1..Flag_Width loop
Put("-");
end loop;
New_Line;
end V_Columns;
The output of the program is:
Enter the number of cross rows (minimum is 3): 7
------------------
| |
| + + |
| + + |
| + + |
| + + |
| + + |
| + + |
| + |
| |
------------------
You could also choose an approach in which the definition of the pattern (here: a flag) and the output mechanism are almost completely decoupled. This approach also allows you to parallelize the flag rendering in case you need to render really, really huge flags ;-):
main.adb
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
N : constant := 2;
Width : constant := 3 + 2 * N;
Height : constant := 3 + 1 * N;
type Screen_X is new Natural range 0 .. Width - 1;
type Screen_Y is new Natural range 0 .. Height - 1;
-------------
-- Pattern --
-------------
function Pattern (X : Screen_X; Y : Screen_Y) return Character is
Is_Border_LR : constant Boolean :=
X = Screen_X'First or else X = Screen_X'Last;
Is_Border_TB : constant Boolean :=
Y = Screen_Y'First or else Y = Screen_Y'Last;
-- The V-Shape is based on the implicit function:
--
-- abs (X - X0) + (Y - Y0) = 0
X0 : constant := (Screen_X'Last + Screen_X'First) / 2;
Y0 : constant := Screen_Y'Last - 1;
Is_V_Shape : constant Boolean :=
Integer (abs (X - X0)) + Integer (Y - Y0) = 0;
begin
if Is_Border_LR and Is_Border_TB then
return '+';
elsif Is_Border_LR then
return '!';
elsif Is_Border_TB then
return '-';
elsif Is_V_Shape then
return '+';
else
return ' ';
end if;
end Pattern;
begin
-- The Render loop.
for Y in Screen_Y loop
for X in Screen_X loop
Put (Pattern (X, Y));
end loop;
New_Line;
end loop;
end Main;
output (N = 1)
$ ./main
+---+
!+ +!
! + !
+---+
output (N = 2)
$ ./main
+-----+
!+ +!
! + + !
! + !
+-----+

Skipping calculation of somes primes when asking lot of primes

I just started to learn some ada code and would create my very own primes calculator.
To procress, I use one of most known method, which is :
"each primes is a result of 6 * x -+ 1 "
So this is my code :
with Ada.Text_IO, Ada.Integer_Text_IO ;
use Ada.Text_IO, Ada.Integer_Text_IO ;
procedure main is
count_prime : Integer := 0 ;
counter : Integer := 1 ;
wanted : Integer ;
iteration : Integer := 0 ;
testing : Integer := 0 ;
is_prime : Boolean ;
answer : Character ;
begin
loop
Put("Prime calculator") ;
New_line(2) ;
Put("Put 'p' to process") ;
New_Line(1);
Put("Put 'q' to quit") ;
New_Line(2) ;
Put(">> ") ;
Get(answer) ;
if answer = 'p' then
Put("Enter wanted primes :");
Get(wanted) ;
Skip_line ;
if wanted > 0 then
Put("2");
New_Line(1);
if wanted > 1 then
Put("3");
New_Line(1);
end if ;
if wanted > 2 then
count_prime := 2;
loop
if counter = 1 then
counter := 0 ;
iteration := iteration + 1 ;
testing := ( 6 * iteration ) - 1 ;
else
counter := 1 ;
testing := ( 6 * iteration ) + 1 ;
end if ;
is_prime := True ;
for i in 2..(testing-1) loop
if (testing rem i = 0) then
is_prime := False ;
end if ;
end loop;
if is_prime = True then
Put(testing);
New_Line(1);
count_prime := count_prime + 1 ;
end if ;
exit when count_prime = wanted;
end loop ;
end if;
Put("Ended") ;
else
Put("It's can't be a negative number");
end if ;
end if ;
New_Line(3);
exit when answer = 'q' ;
end loop ;
end main ;
I really know this is a basic, I mean ouh, extremely basic program. But I would just solve the problem I've asked :
with 'p' and 2 :
2
3
with 'p' and '7'
2
3
5
7
11
13
17
with 'p' and 1200
2
3
19
23
29
31
37
41
....
Where are gone all primes between 3 and 19 ?
You keep running the calculation in a cycle, but do not reset it's initial state. The loop that performs the calculation continues using values of iteration, counter and a few other variables from the previous run.
Either decompose the loop into a separate procedure, or at least surround it with declare block, e.g.:
declare
count_prime : Integer := 2;
counter : Integer := 1;
iteration : Integer := 0;
testing : Integer := 0;
is_prime : Boolean;
begin
loop
ā€¦
end loop;
end;
However, I'd strongly recommend decomposing into a separate procedure.
if wanted > 2 then
count_prime := 2;
-- you probably want to reset iteration here...
iteration := 0;
loop
if counter = 1 then

Wrong answer from spigot algorithm

I'm coding the spigot algorithm for displaying digits of pi in ada, but my output is wrong and I can't figure out why
I've tried messing with the range of my loops and different ways to output my data but nothings worked properly
with ada.integer_text_io; use ada.integer_text_io;
with Ada.Text_IO; use Ada.Text_IO;
procedure Spigot is
n : constant Integer := 1000;
length : constant Integer := 10*n/3+1;
x,q,nines,predigit :Integer :=0;
a: array (0..length) of Integer;
begin
nines:=0;
predigit:=0;
for j in 0..length loop
a(j):=2;
end loop;
for j in 1..n loop
q:=0;
for i in reverse 1..length loop
x:=10*a(i) + q*i;
a(i):= x mod (2*i-1);
q:= x/(2*i-1);
end loop;
a(1):= q mod 10;
q:=q/10;
if q = 9 then
nines:=nines+1;
elsif q = 10 then
put(predigit+1);
for k in 0..nines loop
put("0");
end loop;
predigit:=0;
nines:=0;
else
put(predigit);
predigit:=q;
if nines/=0 then
for k in 0..nines loop
put("9");
end loop;
nines:=0;
end if;
end if;
end loop;
put(predigit);
end Spigot;
so it should just be displayed at 0 3 1 4 1 5 9 2 6 5 3 5 8 9... but the output i get is 0 3 1 4 1 599 2 6 5 3 5 89... it should only be 1 digit at a time and also the outputted values for pi aren't completely correct
I don't know the algorithm well enough to talk about why the digits are off, but I did notice some issues:
Your array is defined with bounds 0 .. Length, which would give you 1 extra element
In your loop that does the calculation, you loop from 1..length, which is ok, but you don't adjust the variable i consistently. The array indices need to be one less than the i's used in the actual calculations (keep in mind they still have to be correctly in bounds of your array). For example
x:=10*a(i) + q*i;
needs to either be
x:=10*a(i-1) + q*i;
or
x:=10*a(i) + q*(i+1);
depending on what you decide your array bounds to be. This applies to multiple lines in your code. See this Stackoverflow thread
You assign A(1) when your array starts at 0
Your loops to print out "0" and "9" should be either 1..length or 0 .. length-1
When you print the digits using Integer_Text_IO.Put, you need to specify a width of 1 to get rid of the spaces
There might be more, that's all I saw.
I think you are translating this answer.
You need to be more careful of your indices and your loop ranges; for example, youā€™ve translated
for(int i = len; i > 0; --i) {
int x = 10 * A[i-1] + q*i;
A[i-1] = x % (2*i - 1);
q = x / (2*i - 1);
}
as
for i in reverse 1..length loop
x:=10*a(i) + q*i;
a(i):= x mod (2*i-1);
q:= x/(2*i-1);
end loop;
The loop ranges are the same. But in the seocnd line, the C code uses A[i-1], whereas yours uses a(i); similarly in the third line.
Later, for
for (int k = 0; k < nines; ++k) {
printf("%d", 0);
}
you have
for k in 0..nines loop
put("0");
end loop;
in which the C loop runs from 0 to nines - 1, but yours runs from 0 to nines. So you put out one more 0 than you should (and later on, likewise for 9s).
Also, you should use put (predigit, width=> 0).

SPARK Integer overflow check

I have the following program:
procedure Main with SPARK_Mode is
F : array (0 .. 10) of Integer := (0, 1, others => 0);
begin
for I in 2 .. F'Last loop
F (I) := F (I - 1) + F (I - 2);
end loop;
end Main;
If I run gnatprove, I get the following result, pointing to the + sign:
medium: overflow check might fail
Does this mean that F (I - 1) could be equal to Integer'Last, and adding anything to that would overflow? If so, then is it not clear from the flow of the program that this is impossible? Or do I need to specify this with a contract? If not, then what does it mean?
A counterexample shows that indeed gnatprove in this case worries about the edges of Integer:
medium: overflow check might fail (e.g. when F = (1 => -1, others => -2147483648) and I = 2)
Consider adding a loop invariant to your code. The following is an example from the book "Building High Integrity Applications with Spark".
procedure Copy_Into(Buffer : out Buffer_Type;
Source : in String) is
Characters_To_Copy : Buffer.Count_Type := Maximum_Buffer_Size;
begin
Buffer := (Others => ' '); -- Initialize to all blanks
if Source'Length < Characters_To_Copy then
Characters_To_Copy := Source'Length;
end if;
for Index in Buffer.Count_Type range 1..Characters_To_Copy loop
pragma Loop_Invariant
(Characters_To_Copy <= Source'Length and
Characters_To_Copy = Characters_To_Copy'Loop_Entry);
Buffer (Index) := Source(Source'First + (Index - 1));
end loop;
end Copy_Into;
This is already an old question, but I would like to add an answer anyway (just for future reference).
With the advancement of provers, the example as stated in the question now proves out-the-box in GNAT CE 2019 (i.e. no loop invariant needed). A somewhat more advanced example can also be proven:
main.adb
procedure Main with SPARK_Mode is
-- NOTE: The theoretical upper bound for N is 46 as
--
-- Fib (46) < 2**31 - 1 < Fib (47)
-- 1_836_311_903 < 2_147_483_647 < 2_971_215_073
-- NOTE: Proved with Z3 only. Z3 is pretty good in arithmetic. Additional
-- options for gnatprove:
--
-- --prover=Z3 --steps=0 --timeout=10 --report=all
type Seq is array (Natural range <>) of Natural;
function Fibonacci (N : Natural) return Seq with
Pre => (N in 2 .. 46),
Post => (Fibonacci'Result (0) = 0)
and then (Fibonacci'Result (1) = 1)
and then (for all I in 2 .. N =>
Fibonacci'Result (I) = Fibonacci'Result (I - 1) + Fibonacci'Result (I - 2));
---------------
-- Fibonacci --
---------------
function Fibonacci (N : Natural) return Seq is
F : Seq (0 .. N) := (0, 1, others => 0);
begin
for I in 2 .. N loop
F (I) := F (I - 1) + F (I - 2);
pragma Loop_Invariant
(for all J in 2 .. I =>
F (J) = F (J - 1) + F (J - 2));
-- NOTE: The loop invariant below helps the prover to proof the
-- absence of overflow. It "reminds" the prover that all values
-- from iteration 3 onwards are strictly monotonically increasing.
-- Hence, if absence of overflow is proven in this iteration,
-- then absence is proven for all previous iterations.
pragma Loop_Invariant
(for all J in 3 .. I =>
F (J) > F (J - 1));
end loop;
return F;
end Fibonacci;
begin
null;
end Main;
This loop invariant should work - since 2^(n-1) + 2^(n-2) < 2^n - but I can't convince the provers:
procedure Fibonacci with SPARK_Mode is
F : array (0 .. 10) of Natural := (0 => 0,
1 => 1,
others => 0);
begin
for I in 2 .. F'Last loop
pragma Loop_Invariant
(for all J in F'Range => F (J) < 2 ** J);
F (I) := F (I - 1) + F (I - 2);
end loop;
end Fibonacci;
You can probably convince the provers with a bit of manual assistance (showing how 2^(n-1) + 2^(n-2) = 2^(n-2) * (2 + 1) = 3/4 * 2^n < 2^n).

Resources