Skip to content

Commit a8636eb

Browse files
Merge branch 'main' of github.com:corneliusdavid/1BRC-Delphi into main
# Conflicts: # entries/dcornelius/src/uChallengeCommon.pas
2 parents bcea001 + 199a9ef commit a8636eb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4482
-1017
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/profiling
55
/results
66
/entries/entries.json
7-
*_all.*
7+
*.sh
88

99
# Compiled l10n files: .mo should be ignored
1010
*.mo

README.md

Lines changed: 25 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# 1️⃣🐝🏎️ The One Billion Row Challenge in Object Pascal
22
<p>
3-
<a href="https://discord.gg/c382VBk"><img src="https://img.shields.io/discord/623794270255579146?label=Delphi Community Discord" alt="Delphi Community" /></a>
4-
<a href="https://discord.gg/3VdxbSFyJP"><img src="https://img.shields.io/discord/570025060312547359?label=Unofficial Free Pacal Discord" alt="Unofficial Free Pacal" /></a>
3+
<a href="https://discord.gg/c382VBk"><img src="https://img.shields.io/discord/623794270255579146?label=Delphi Community&logo=discord" alt="Delphi Community" /></a>
4+
<a href="https://discord.gg/3VdxbSFyJP"><img src="https://img.shields.io/discord/570025060312547359?label=Unofficial Free Pascal&logo=discord" alt="Unofficial Free Pacal" /></a>
5+
<a href="https://t.me/delphidevelopers"><img src="https://img.shields.io/badge/Telegram-Delphi_Developers-blue?logo=telegram" /></a>
6+
<a href="https://t.me/freepascal_en"><img src="https://img.shields.io/badge/Telegram-Free_Pascal_&_Lazarus-blue?logo=telegram" /></a>
57
<a href="https://forum.lazarus.freepascal.org/index.php/topic,66571.0.html"><img src="https://img.shields.io/badge/Lazarus_Forum-1BRC_Thread-blue" /></a>
68
<a href="https://en.delphipraxis.net/topic/11209-offical-launch-of-the-1-billion-row-challenge-in-object-pascal/"><img src="https://img.shields.io/badge/Delphi_Praxis_Forum-1BRC_Thread-blue" /></a>
79
</p>
@@ -31,7 +33,7 @@ Conakry;31.2
3133
Istanbul;23.0
3234
```
3335

34-
The task is to write an Object Pascal program which reads the file, calculates the min, mean, and max temperature value per weather station, and emits the results on `STDOUT` like this (i.e., sorted alphabetically by station name, and the result values per station in the format `<min>/<mean>/<max>`, rounded to one fractional digit towards positive infinity with both `17.01` and `17.05` being rounded to `17.1`, with the decimal separator being a period `.`):
36+
The task is to write an Object Pascal program which reads the file, calculates the min, mean, and max temperature value per weather station, and emits the results on `STDOUT` like this (i.e., sorted alphabetically by station name, and the result values per station in the format `<min>/<mean>/<max>`, rounded to one fractional digit, with the decimal separator being a period `.`, and for that you can chose one of the options presented in the [Rounding Section](#rounding) or implement your own that is consistent with the options provided.):
3537

3638
```
3739
{Abha=-23.0/18.0/59.2, Abidjan=-16.2/26.0/67.3, Abéché=-10.0/29.4/69.0, Accra=-10.1/26.4/66.4, Addis Ababa=-23.7/16.0/67.0, Adelaide=-27.8/17.3/58.5, ...}
@@ -68,53 +70,11 @@ Submit your implementation and become part of the leader board!
6870

6971
## Rounding
7072

71-
While I recognize that Székely's rounding code was a good effort, it was not simple and made a lot of people doubt it was even correct for negative temperatures.\
72-
In a discussion with [Mr. Packman](https://pack.ac/) themselves, we came up with a simpler solution. They even added some _Unit Testing_ :D.
73-
74-
This will be the official way to round the output values, so pick your poison:
75-
```pas
76-
function RoundEx(x: Double): Double; inline;
77-
begin
78-
Result := Ceil(x * 10) / 10;
79-
end;
80-
81-
function RoundExInteger(x: Double): Integer; inline;
82-
begin
83-
Result := Ceil(x * 10);
84-
end;
85-
86-
function RoundExString(x: Double): String; inline;
87-
var
88-
V, Q, R: Integer;
89-
begin
90-
V := RoundExInteger(x);
91-
if V < 0 then
92-
begin
93-
Result := '-';
94-
V := -V;
95-
end
96-
else
97-
Result := '';
98-
Q := V div 10;
99-
R := V - (Q * 10);
100-
Result := IntToStr(Q) + '.' + IntToStr(R);
101-
end;
102-
103-
procedure Test;
104-
var
105-
F: Double;
106-
begin
107-
for F in [10.01, 10.04, -10.01, -10.0, 0, -0, -0.01] do
108-
WriteLn(RoundExInteger(F), ' ', RoundExString(F), ' ', RoundEx(F));
109-
//101 10.1 1.0100000000000000E+001
110-
//101 10.1 1.0100000000000000E+001
111-
//-100 -10.0 -1.0000000000000000E+001
112-
//-100 -10.0 -1.0000000000000000E+001
113-
//0 0.0 0.0000000000000000E+000
114-
//0 0.0 0.0000000000000000E+000
115-
//0 0.0 0.0000000000000000E+000
116-
end;
117-
```
73+
With the help of this magnificent community, we were able to finally get to a rounding solution that works.
74+
75+
This means that I'm encouraging everyone to use the code that is now in the [Baseline.Common](baseline/Common) unit.\
76+
I do have to make crystal clear that using that code is an **option**, one that you can always opt out of.\
77+
But if you do opt in, just include that unit in your entry and job's a done.
11878

11979
## Generating the measurements.txt
12080
> **NOTE**
@@ -162,12 +122,12 @@ Expected `SHA256` hash:
162122
`ebad17b266ee9f5cb3d118531f197e6f68c9ab988abc5cb9506e6257e1a52ce6`
163123

164124
## Verify Output File
165-
> **NOTE**
166-
>
167-
> We are still waiting for the Delphi version to be completed in order for us to have an official `SHA256` hash for the output.
168-
>
169-
> Until then, this is the current one: `4256d19d3e134d79cc6f160d428a1d859ce961167bd01ca528daca8705163910`
170-
> There's also an archived version of the [baseline output](./data/baseline.output.gz)
125+
126+
There is now a Delphi version of the baseline. This means that we now have an official way of generating a valid output on both sides of the fence.
127+
128+
With this, we now have the official hash: `4256d19d3e134d79cc6f160d428a1d859ce961167bd01ca528daca8705163910`
129+
130+
There's also an archived version of the [baseline output](./data/baseline.output.gz)
171131

172132
## Differences From Original
173133
I've decided that I would want this challenge to be turned way up to 11!
@@ -194,11 +154,13 @@ These are the results from running all entries into the challenge on my personal
194154

195155
| # | Result (m:s.ms) | Compiler | Submitter | Notes | Certificates |
196156
|--:|----------------:|---------:|:----------|:------|:-------------|
197-
| 1 | 0:1.7599 | lazarus-3.0, fpc-3.2.2 | Arnaud Bouchez | Using `mORMot2`, 32 threads | |
198-
| 2 | 0:16.874 | lazarus-3.0, fpc-3.2.2 | Székely Balázs | Using 32 threads | |
199-
| 3 | 0:20.0693 | lazarus-3.0, fpc-3.2.2 | Lurendrejer Aksen | Using 32 threads | |
200-
| 4 | 1:16.059 | lazarus-3.0, fpc-3.2.2 | Richard Lawson | Using 1 thread | |
201-
| 5 | 12:37.7864 | lazarus-3.0, fpc-3.2.2 | Iwan Kelaiah | Using 1 thread | |
157+
| 1 | 0:1.971 | lazarus-3.0, fpc-3.2.2 | Arnaud Bouchez | Using `mORMot2`, 32 threads | |
158+
| 2 | 0:20.960 | lazarus-3.0, fpc-3.2.2 | Székely Balázs | Using 32 threads | |
159+
| 3 | 0:23.158 | lazarus-3.0, fpc-3.2.2 | Lurendrejer Aksen | Using 32 threads **(failed hash)** | |
160+
| 4 | 1:23.684 | lazarus-3.0, fpc-3.2.2 | Richard Lawson | Using a single thread | |
161+
| 5 | 5:2.512 | lazarus-3.0, fpc-3.2.2 | Iwan Kelaiah | Using a single thread | |
162+
| 6 | 7:54.606 | delphi 12.1 | David Cornelius | Using 1 threads **(failed hash)** | |
163+
| 7 | 10:55.724 | delphi 12.1 | Brian Fire | Using 1 threads | |
202164

203165
> **NOTE**
204166
>
@@ -230,7 +192,8 @@ I'd like to thank [@mobius](https://github.com/mobius1qwe) for taking the time t
230192
I'd like to thank [@dtpfl](https://github.com/dtpfl) for his invaluable work on maintaining the `README.md` file up to date with everything.\
231193
I'd like to thank Székely Balázs for providing many patches to make everything compliant with the original challenge.\
232194
I'd like to thank [@corneliusdavid](https://github.com/corneliusdavid) for giving some of the information files a once over and making things more legible and clear.\
233-
I'd like to thank Mr. **Pack**man, aka O, for clearing the fog around the rounding issues.
195+
I'd like to thank Mr. **Pack**man, aka O, for clearing the fog around the rounding issues.\
196+
I'd like to thank [Georges](https://github.com/georges-hatem) for providing us with the Delphi version of baseline.
234197

235198
## Links
236199
The original repository: https://github.com/gunnarmorling/1brc \

baseline/Common/baseline.common.pas

Lines changed: 17 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -7,219 +7,37 @@
77
interface
88

99
uses
10-
Classes
11-
, SysUtils
12-
{$IFDEF FPC}
13-
, Contnrs
14-
{$ELSE}
15-
{$ENDIF}
16-
10+
{$IFDEF FPC}
11+
SysUtils
12+
{$ELSE}
13+
System.SysUtils
14+
{$ENDIF}
1715
;
1816

19-
type
20-
{ TWeatherStation }
21-
PWeatherStation = ^TWeatherStation;
22-
TWeatherStation = record
23-
FStation: String[100];
24-
FMin: Int64;
25-
FMax: Int64;
26-
FTot: Int64;
27-
FCnt: Integer;
28-
29-
end;
30-
{ TBaseline }
31-
TBaseline = class(TObject)
32-
private
33-
FInputFile: String;
34-
FStationNames: TStringList;
35-
FHashStationList: TFPHashList;
36-
procedure AddToHashList(AStation: String; ATemp: Int64);
37-
procedure BuildHashList;
38-
function RoundEx(x: Double): Double;
39-
protected
40-
public
41-
constructor Create(AInputFile: String);
42-
destructor Destroy; override;
43-
44-
procedure Generate;
45-
published
46-
end;
47-
48-
{$IFNDEF FPC}
49-
TStringArray = array of Utf8String;
50-
TWriteBufStream = TFileStream;
51-
{$ENDIF}
17+
function RoundExDouble(const ATemp: Double): Double;
18+
function RoundExInteger(const ATemp: Double): Integer;
5219

5320
implementation
5421

55-
uses
56-
Math
57-
{$IFDEF FPC}
58-
, streamex
59-
{$ELSE}
60-
, System.Diagnostics
61-
{$IF defined(MSWINDOWS)}, Winapi.Windows{$ENDIF}
62-
{$ENDIF}
63-
;
64-
65-
const
66-
//lineEnding = #13#10;
67-
stationsCapacity = 50000;
68-
69-
70-
function Compare(AList: TStringList; AIndex1, AIndex2: Integer): Integer;
71-
var
72-
Pos1, Pos2: Integer;
73-
Str1, Str2: String;
74-
begin
75-
Result := 0;
76-
Str1 := AList.Strings[AIndex1];
77-
Str2 := AList.Strings[AIndex2];
78-
Pos1 := Pos('=', Str1);
79-
Pos2 := Pos('=', Str2);
80-
if (Pos1 > 0) and (Pos2 > 0) then
81-
begin
82-
Str1 := Copy(Str1, 1, Pos1 - 1);
83-
Str2 := Copy(Str2, 1, Pos2 - 1);
84-
Result := CompareStr(Str1, Str2);
85-
end;
86-
end;
87-
88-
{ TBaseline }
89-
90-
constructor TBaseline.Create(AInputFile: String);
91-
begin
92-
FInputFile := AInputFile;
93-
94-
FHashStationList:= TFPHashList.Create;
95-
FHashStationList.Capacity:= stationsCapacity;
96-
97-
FStationNames := TStringList.Create;
98-
FStationNames.Capacity := stationsCapacity;
99-
FStationNames.UseLocale := False;
100-
end;
101-
102-
destructor TBaseline.Destroy;
103-
var
104-
index: Integer;
105-
begin
106-
FStationNames.Free;
107-
for index:= 0 to FHashStationList.Count - 1 do
108-
begin
109-
Dispose(PWeatherStation(FHashStationList.Items[index]));
110-
end;
111-
FHashStationList.Free;
112-
inherited Destroy;
113-
end;
114-
115-
procedure TBaseline.AddToHashList(AStation: String; ATemp: Int64);
116-
var
117-
weatherStation: PWeatherStation;
118-
Index: Integer;
22+
function Ceiling(const ANumber: Double): integer; inline;
11923
begin
120-
Index := FHashStationList.FindIndexOf(AStation);
121-
if Index = -1 then
122-
begin
123-
New(weatherStation);
124-
weatherStation^.FStation := AStation;
125-
weatherStation^.FMin := ATemp;
126-
weatherStation^.FMax := ATemp;
127-
weatherStation^.FTot := ATemp;
128-
weatherStation^.FCnt := 1;
129-
FHashStationList.Add(AStation, weatherStation);
130-
end
131-
else
132-
begin
133-
weatherStation := FHashStationList.Items[Index];
134-
weatherStation^.FMin := Min(weatherStation^.FMin, ATemp);
135-
weatherStation^.FMax := Max(weatherStation^.FMax, ATemp);
136-
weatherStation^.FTot := weatherStation^.FTot + ATemp;
137-
weatherStation^.FCnt := weatherStation^.FCnt + 1;
138-
end;
24+
Result := Trunc(ANumber) + Ord(Frac(ANumber) > 0);
13925
end;
14026

141-
procedure TBaseline.BuildHashList;
27+
function RoundExDouble(const ATemp: Double): Double; inline;
14228
var
143-
inputFileStream: TFileStream;
144-
streamReader: TStreamReader;
145-
position, Code: Integer;
146-
strLine: String;
147-
strStation: String;
148-
strTemp: String;
149-
temparature: Int64;
150-
begin
151-
if FileExists(FInputFile) then
152-
begin
153-
inputFileStream:= TFileStream.Create(FInputFile, fmOpenRead);
154-
try
155-
streamReader:= TStreamReader.Create(inputFileStream);
156-
try
157-
while not streamReader.Eof do
158-
begin
159-
strLine:= streamReader.ReadLine;
160-
position := Pos(';', strLine);
161-
if position > 0 then
162-
begin
163-
strStation := Copy(strLine, 1, position - 1);
164-
strTemp := Copy(strLine, position + 1, Length(strLine));
165-
strTemp := StringReplace(strTemp, '.', '', [rfReplaceAll]);
166-
Val(strTemp, temparature, Code);
167-
if Code <> 0 then
168-
Continue;
169-
AddToHashList(strStation, temparature);
170-
end;
171-
end;
172-
finally
173-
streamReader.Free;
174-
end;
175-
finally
176-
inputFileStream.Free;
177-
end;
178-
end
179-
else
180-
begin
181-
raise Exception.Create(Format('File "%s" not found.', [FInputFile]));
182-
end;
183-
end;
184-
185-
function TBaseline.RoundEx(x: Double): Double;
29+
tmp: Double;
18630
begin
187-
Result := Ceil(x * 10) / 10;
31+
tmp:= ATemp * 10;
32+
Result := Ceiling(tmp) / 10;
18833
end;
18934

190-
procedure TBaseline.Generate;
35+
function RoundExInteger(const ATemp: Double): Integer; inline;
19136
var
192-
index: Integer;
193-
strTemp: String;
194-
min: Double;
195-
max: Double;
196-
mean: Double;
197-
weatherStation: PWeatherStation;
37+
tmp: Double;
19838
begin
199-
200-
BuildHashList;
201-
202-
FStationNames.BeginUpdate;
203-
for index := 0 to FHashStationList.Count - 1 do
204-
begin
205-
weatherStation := FHashStationList.Items[index];
206-
Min := RoundEx(weatherStation^.FMin/10);
207-
Max := RoundEx(weatherStation^.FMax/10);
208-
Mean := RoundEx(weatherStation^.FTot/weatherStation^.FCnt/10);
209-
strTemp := weatherStation^.FStation + '=' + FormatFloat('0.0', Min) + '/' + FormatFloat('0.0', Mean) + '/' + FormatFloat('0.0', Max) + ',';
210-
FStationNames.Add(strTemp);
211-
end;
212-
FStationNames.EndUpdate;
213-
FStationNames.CustomSort(@Compare);
214-
215-
strTemp:= '';
216-
for index:= 0 to FStationNames.Count - 1 do
217-
begin
218-
strTemp:= strTemp + FStationNames[index] + ' ';
219-
end;
220-
SetLength(strTemp, Length(strTemp) - 2);
221-
WriteLn('{', strTemp, '}');
222-
39+
tmp:= ATemp * 10;
40+
Result := Ceiling(tmp);
22341
end;
22442

22543
end.

0 commit comments

Comments
 (0)