diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/haversine_generator/haversine_generator.cpp | 243 | ||||
| -rw-r--r-- | src/haversine_generator/haversine_random.h | 43 | ||||
| -rwxr-xr-x | src/haversine_processor/build.sh | 2 | ||||
| -rw-r--r-- | src/haversine_processor/haversine_processor.cpp | 212 |
4 files changed, 260 insertions, 240 deletions
diff --git a/src/haversine_generator/haversine_generator.cpp b/src/haversine_generator/haversine_generator.cpp index e0bc37a..3ce2f11 100644 --- a/src/haversine_generator/haversine_generator.cpp +++ b/src/haversine_generator/haversine_generator.cpp @@ -21,23 +21,27 @@ POP_WARNINGS //~ Macro's #define MemoryCopy memcpy - -//~ Constants -#define ClusterCount 64 -// NOTE(luca): A double's mantissa is 52 bits. 2^52 - 1 is 4503599627370495 which has -// 16 digits. -#define PointJsonFormat "{ \"x0\": %.15f, \"y0\": %.15f, \"x1\": %.15f, \"y1\": %.15f }\n" - //~ Types #include "generated/types.h" -struct cluster +//~ Helpers + +void WriteMemoryTofile(umm Size, void *Memory, umm PairCount, char *Name, char *Extension) { - f64 X; - f64 Y; - f64 Width; - f64 Height; -}; + char FileName[256] = {}; + stbsp_sprintf(FileName, "data_%lu_%s.%s", PairCount, Name, Extension); + + int File = open(FileName, O_RDWR|O_CREAT|O_TRUNC, 0600); + if(File != -1) + { + smm BytesWritten = write(File, Memory, Size); + Assert(BytesWritten == Size); + } + else + { + + } +} //~ Main int main(int ArgsCount, char *Args[], char *Env[]) @@ -49,52 +53,35 @@ int main(int ArgsCount, char *Args[], char *Env[]) u32 Method = 0; u64 RandomSeed = 0;; u64 PairCount = 0; - b32 Error = false; - char *MethodString = Args[1]; + char *MethodName = Args[1]; char *SeedString = Args[2]; - char *PairCountString = Args[3]; - if(!strcmp(MethodString, "uniform")) - { - Method = Method_Uniform; - } - else if(!strcmp(MethodString, "cluster")) - { - Method = Method_Cluster; - } - else - { - Error = true; - } + u64 ClusterCountLeft = U64Max; - RandomSeed = atoll(SeedString); + f64 MaxAllowedX = 180.0; + f64 MaxAllowedY = 90.0; + f64 XCenter = 0.0; + f64 YCenter = 0.0; + f64 XRadius = MaxAllowedX; + f64 YRadius = MaxAllowedY; - if(RandomSeed == 0) + if(!strcmp(MethodName, "cluster")) { - if(SeedString[0] == '0') - { - RandomSeed = 0; - } - else - { - Error = true; - } + ClusterCountLeft = 0; } - - PairCount = atoll(PairCountString); - if(PairCount == 0) + else if(strcmp(MethodName, "uniform")) { - Error = true; + MethodName = "uniform"; + printf("Warning: Unknown method '%s', uniform used.\n", MethodName); } - if(!Error) + RandomSeed = atoll(Args[2]); + PairCount = atoll(Args[3]); + + u64 MaxPairCount = (1LL << 34); + if(PairCount < MaxPairCount) { - printf("Method: %s\n" - "Random seed: %lu\n" - "Pairs count: %lu\n" - , MethodString, RandomSeed, PairCount); - umm JsonMemorySize = Gigabytes(4); u8 *JsonMemory = (u8 *)mmap(0, JsonMemorySize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0); u8 *JsonOut = JsonMemory; @@ -103,141 +90,69 @@ int main(int ArgsCount, char *Args[], char *Env[]) u8 *BinMemory = (u8 *)mmap(0, BinMemorySize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0); u8 *BinOut = BinMemory; - // Generate pairs in the following format. - // - // { - // "pairs": - // [ - // { "x0": ..., "y0": ..., "x1": ..., "y1": ... }, - // { "x0": ..., "y0": ..., "x1": ..., "y1": ... } - // ] - // } - // + JsonOut += stbsp_sprintf((char *)JsonOut, + "{\n" + " \"pairs\":\n" + " [\n"); - char *JsonHeader = - "{\n" - " \"pairs\":\n" - " [\n"; - char *JsonFooter = - " ]\n" - "}\n"; + pcg64_random_t Series = {}; + pcg64_srandom_r(&Series, RandomSeed, RandomSeed); - JsonOut += stbsp_sprintf((char *)JsonOut, "%s", JsonHeader); + u64 ClusterCountMax = 1 + (PairCount / 64); - pcg64_random_t RNG = {}; - pcg64_srandom_r(&RNG, RandomSeed, RandomSeed); + f64 SumCoefficient = 1.0/(f64)PairCount; + f64 Sum = 0; - if(0) {} - else if(Method == Method_Uniform) + for(u32 PairIndex = 0; + PairIndex < PairCount; + PairIndex += 1) { - f64 AverageSum = 0; - f64 TotalSum = 0; - for(u64 PairsIndex = 0; - PairsIndex < PairCount; - PairsIndex += 1) + if(ClusterCountLeft-- == 0) { - f64 X0 = RandomBetween(&RNG, -180.0, 180.0); - f64 Y0 = RandomBetween(&RNG, -90.0, 90.0); - f64 X1 = RandomBetween(&RNG, -180.0, 180.0); - f64 Y1 = RandomBetween(&RNG, -90.0, 360.0); - - f64 Sum = ReferenceHaversine(X0, Y0, X1, Y1, 6372.8); - TotalSum += Sum; - - *(f64 *)BinOut = Sum; - BinOut += sizeof(Sum); + ClusterCountLeft = ClusterCountMax; - JsonOut += stbsp_sprintf((char *)JsonOut, " " PointJsonFormat, X0, Y0, X1, Y1); + XCenter = RandomBetween(&Series, -MaxAllowedX, MaxAllowedX); + YCenter = RandomBetween(&Series, -MaxAllowedY, MaxAllowedY); + XRadius = RandomBetween(&Series, 0, MaxAllowedX); + YRadius = RandomBetween(&Series, 0, MaxAllowedY); } - AverageSum = TotalSum / (f64)PairCount; - *(f64 *)BinOut = AverageSum; - BinOut += sizeof(AverageSum); + f64 X0 = RandomDegree(&Series, XCenter, XRadius, MaxAllowedX); + f64 Y0 = RandomDegree(&Series, YCenter, YRadius, MaxAllowedY); + f64 X1 = RandomDegree(&Series, XCenter, XRadius, MaxAllowedX); + f64 Y1 = RandomDegree(&Series, YCenter, YRadius, MaxAllowedY); - printf("Average sum: %f\n", AverageSum); - } - else if(Method == Method_Cluster) - { - cluster Clusters[ClusterCount] = {}; - for(u32 ClusterIndex = 0; - ClusterIndex < ClusterCount; - ClusterIndex += 1) - { - cluster *ClusterAt = Clusters + ClusterIndex; - ClusterAt->X = RandomBetween(&RNG, -180.0, 180.0); - ClusterAt->Y = RandomBetween(&RNG, -90.0, 90.0); - ClusterAt->Width = RandomBetween(&RNG, 0.0, 180.0); - ClusterAt->Height = RandomBetween(&RNG, 0.0, 90.0); - } - - f64 AverageSum = 0; - f64 TotalSum = 0; - u32 ClusterIndex = 0; - for(u32 PairIndex = 0; - PairIndex < PairCount; - PairIndex += 1) - { - cluster *ClusterAt = Clusters + ClusterIndex; - - f64 X0 = RandomBetween(&RNG, ClusterAt->X - ClusterAt->Width, ClusterAt->X + ClusterAt->Width); - f64 Y0 = RandomBetween(&RNG, ClusterAt->Y - ClusterAt->Height, ClusterAt->Y + ClusterAt->Height); - f64 X1 = RandomBetween(&RNG, ClusterAt->X - ClusterAt->Width, ClusterAt->X + ClusterAt->Width); - f64 Y1 = RandomBetween(&RNG, ClusterAt->Y - ClusterAt->Height, ClusterAt->Y + ClusterAt->Height); - - f64 Sum = ReferenceHaversine(X0, Y0, X1, Y1, 6372.8); - TotalSum += Sum; - - *(f64 *)BinOut = Sum; - BinOut += sizeof(Sum); - - JsonOut += stbsp_sprintf((char *)JsonOut, " " PointJsonFormat, X0, Y0, X1, Y1); - - ClusterIndex += 1; - if(ClusterIndex == ClusterCount) - { - ClusterIndex -= ClusterCount; - } - - } - AverageSum = TotalSum / (f64)PairCount; + f64 EarthRadius = 6372.8; + f64 Distance = ReferenceHaversine(X0, Y0, X1, Y1, EarthRadius); + Sum += SumCoefficient*Distance; - *(f64 *)BinOut = AverageSum; - BinOut += sizeof(AverageSum); + *(f64 *)BinOut = Distance; + BinOut += sizeof(Distance); - printf("Average sum: %f\n", AverageSum); - } - else - { - Assert(0); + const char *Separator = (PairIndex == PairCount - 1) ? "\n" : ",\n"; + JsonOut += stbsp_sprintf((char *)JsonOut, + " { \"x0\": %.16f, \"y0\": %.16f, \"x1\": %.16f, \"y1\": %.16f }%s", + X0, Y0, X1, Y1, Separator); } - JsonOut += stbsp_sprintf((char *)JsonOut, "%s", JsonFooter); + *(f64 *)BinOut = Sum; + BinOut += sizeof(Sum); - // Write memory to json file - { - char JsonFileName[256] = {}; - stbsp_sprintf(JsonFileName, "data_%lu.json", PairCount); - - int File = open(JsonFileName, O_RDWR|O_CREAT|O_TRUNC, 0600); - Assert(File != -1); - smm Result = write(File, JsonMemory, JsonOut - JsonMemory); - Assert(Result == JsonOut - JsonMemory); - } + printf("Method: %s\n" + "Random seed: %lu\n" + "Pairs count: %lu\n" + , MethodName, RandomSeed, PairCount); + printf("Average sum: %.16f\n", Sum); - // Write memory to binary answer file - char BinFileName[256] = {}; - { - stbsp_sprintf(BinFileName, "data_%lu_haveranswer.f64", PairCount); - int File = open(BinFileName, O_RDWR|O_CREAT|O_TRUNC, 0600); - Assert(File != -1); - smm Result = write(File, BinMemory, BinOut - BinMemory); - Assert(Result == BinOut - BinMemory); - } + JsonOut += stbsp_sprintf((char *)JsonOut, + " ]\n" + "}\n"); + WriteMemoryTofile(JsonOut - JsonMemory, JsonMemory, PairCount, "flex", "json"); + WriteMemoryTofile(BinOut - BinMemory, BinMemory, PairCount, "haveranswer", "f64"); } else { - printf("Usage: %s [uniform/cluster] [random seed] [number of pairs to generate]\n", - Args[0]); + printf("Massive files unsupported. Number of pairs must be less than %lu.\n", MaxPairCount); } } else diff --git a/src/haversine_generator/haversine_random.h b/src/haversine_generator/haversine_random.h index e80df7d..76d766e 100644 --- a/src/haversine_generator/haversine_random.h +++ b/src/haversine_generator/haversine_random.h @@ -5,10 +5,12 @@ POP_WARNINGS #define CountLeadingZeroes64(Value) __builtin_clzll(Value) +typedef pcg64_random_t random_series; + u64 -RandomU64(pcg64_random_t *RNG) +RandomU64(random_series *Series) { - u64 Result = pcg64_random_r(RNG); + u64 Result = pcg64_random_r(Series); return Result; } @@ -30,7 +32,7 @@ RandomU64(pcg64_random_t *RNG) * number in [0, 1], 0.00001010011111010100...; then round it. */ f64 -RandomF64(pcg64_random_t *RNG) +RandomF64(random_series *Series) { s32 Exponent = -64; u64 Significand; @@ -40,7 +42,7 @@ RandomF64(pcg64_random_t *RNG) * Read zeros into the exponent until we hit a one; the rest * will go into the significand. */ - while((Significand = RandomU64(RNG)) == 0) + while((Significand = RandomU64(Series)) == 0) { Exponent -= 64; /* @@ -66,7 +68,7 @@ RandomF64(pcg64_random_t *RNG) if (Shift != 0) { Exponent -= Shift; Significand <<= Shift; - Significand |= (RandomU64(RNG) >> (64 - Shift)); + Significand |= (RandomU64(Series) >> (64 - Shift)); } /* @@ -86,22 +88,41 @@ RandomF64(pcg64_random_t *RNG) } f64 -RandomUnilateral(pcg64_random_t *RNG) +RandomUnilateral(random_series *Series) { - return RandomF64(RNG); + return RandomF64(Series); } f64 -RandomBilateral(pcg64_random_t *RNG) +RandomBilateral(random_series *Series) { - f64 Result = 2.0*RandomUnilateral(RNG) - 1.0; + f64 Result = 2.0*RandomUnilateral(Series) - 1.0; return Result; } f64 -RandomBetween(pcg64_random_t *RNG, f64 Min, f64 Max) +RandomBetween(random_series *Series, f64 Min, f64 Max) { f64 Range = Max - Min; - f64 Result = Min + RandomUnilateral(RNG)*Range; + f64 Result = Min + RandomUnilateral(Series)*Range; + return Result; +} + + +static f64 RandomDegree(random_series *Series, f64 Center, f64 Radius, f64 MaxAllowed) +{ + f64 MinVal = Center - Radius; + if(MinVal < -MaxAllowed) + { + MinVal = -MaxAllowed; + } + + f64 MaxVal = Center + Radius; + if(MaxVal > MaxAllowed) + { + MaxVal = MaxAllowed; + } + + f64 Result = RandomBetween(Series, MinVal, MaxVal); return Result; }
\ No newline at end of file diff --git a/src/haversine_processor/build.sh b/src/haversine_processor/build.sh index 2cd5f25..73991e9 100755 --- a/src/haversine_processor/build.sh +++ b/src/haversine_processor/build.sh @@ -8,7 +8,7 @@ cd "$ScriptDirectory" #- Globals CommonCompilerFlags="-DOS_LINUX=1 -fsanitize-trap -nostdinc++" CommonWarningFlags="-Wall -Wextra -Wconversion -Wdouble-promotion -Wno-sign-conversion -Wno-sign-compare -Wno-double-promotion -Wno-unused-but-set-variable -Wno-unused-variable -Wno-write-strings -Wno-pointer-arith -Wno-unused-parameter -Wno-unused-function" -LinkerFlags="" +LinkerFlags="-lm" DebugFlags="-g -ggdb -g3" ReleaseFlags="-O3" diff --git a/src/haversine_processor/haversine_processor.cpp b/src/haversine_processor/haversine_processor.cpp index 8571627..ffb3a28 100644 --- a/src/haversine_processor/haversine_processor.cpp +++ b/src/haversine_processor/haversine_processor.cpp @@ -2,6 +2,7 @@ #define STB_SPRINTF_IMPLEMENTATION #include "libs/stb_sprintf.h" +#include <math.h> #include <errno.h> #include <unistd.h> @@ -21,6 +22,46 @@ struct str8 global_variable u8 LogBuffer[Kilobytes(64)]; //~ Functions + +//- Haversine +static f64 Square(f64 A) +{ + f64 Result = (A*A); + return Result; +} + +static f64 RadiansFromDegrees(f64 Degrees) +{ + f64 Result = 0.01745329251994329577 * Degrees; + return Result; +} + +// NOTE(casey): EarthRadius is generally expected to be 6372.8 +static f64 ReferenceHaversine(f64 X0, f64 Y0, f64 X1, f64 Y1, f64 EarthRadius) +{ + /* NOTE(casey): This is not meant to be a "good" way to calculate the Haversine distance. + Instead, it attempts to follow, as closely as possible, the formula used in the real-world + question on which these homework exercises are loosely based. + */ + + f64 lat1 = Y0; + f64 lat2 = Y1; + f64 lon1 = X0; + f64 lon2 = X1; + + f64 dLat = RadiansFromDegrees(lat2 - lat1); + f64 dLon = RadiansFromDegrees(lon2 - lon1); + lat1 = RadiansFromDegrees(lat1); + lat2 = RadiansFromDegrees(lat2); + + f64 a = Square(sin(dLat/2.0)) + cos(lat1)*cos(lat2)*Square(sin(dLon/2)); + f64 c = 2.0*asin(sqrt(a)); + + f64 Result = EarthRadius * c; + + return Result; +} + //- Debug utilities void AssertErrnoNotEquals(smm Result, smm ErrorValue) { @@ -51,6 +92,24 @@ void LogFormat(char *Format, ...) AssertErrnoEquals(BytesWritten, Length); } + +str8 ReadEntireFileIntoMemory(char *FileName) +{ + str8 Result = {}; + + int File = open(FileName, O_RDONLY); + + struct stat StatBuffer = {}; + int Error = fstat(File, &StatBuffer); + AssertErrnoNotEquals(Error, -1); + + Result.Size = StatBuffer.st_size; + Result.Data = (u8 *)mmap(0, Result.Size, PROT_READ, MAP_PRIVATE, File, 0); + AssertErrnoNotEquals((smm)Result.Data, (smm)MAP_FAILED); + + return Result; +} + //- Parsing utilities b32 IsWhiteSpace(u8 Char) @@ -169,18 +228,34 @@ void ParseFloatNumber(umm Size, u8 *In, umm *Start, f64 *Value) *Start = At; } +void ConsumeHaversineJsonNumber(umm Size, u8 *In, umm *Start, str8 Name, f64 *Value, b32 NumberLeft) +{ + umm At = *Start; + + ConsumePastJsonString(Size, In, &At, Name); + ConsumeWhiteSpacePastChar(Size, In, &At, ':'); + while(At < Size && IsWhiteSpace(In[At])) At += 1; + ParseFloatNumber(Size, In, &At, Value); + + if(NumberLeft) + { + ConsumeWhiteSpacePastChar(Size, In, &At, ','); + } + + *Start = At; +} + //- int main(int ArgsCount, char *Args[]) { - - char *JsonFileName = 0; - char *AnswersFileName = 0; - + str8 Answers = {}; + umm AnswerIndex = 0; + str8 Json = {}; if(ArgsCount >= 2) { - JsonFileName = Args[1]; + Json = ReadEntireFileIntoMemory(Args[1]); } else { @@ -189,75 +264,84 @@ int main(int ArgsCount, char *Args[]) if(ArgsCount >= 3) { - AnswersFileName = Args[1]; + Answers = ReadEntireFileIntoMemory(Args[2]); } - if(JsonFileName) + if(Json.Size) { - int JsonFile = open(JsonFileName, O_RDONLY); - if(JsonFile != -1) - { - struct stat StatBuffer = {}; - int Result = fstat(JsonFile, &StatBuffer); - AssertErrnoNotEquals(Result, -1); + f64 X0 = 0.0; + f64 X1 = 0.0; + f64 Y0 = 0.0; + f64 Y1 = 0.0; + + // Json Parsing + u8 *In = Json.Data; + + umm At = 0; + ConsumeWhiteSpacePastChar(Json.Size, In, &At, '{'); + ConsumePastJsonString(Json.Size, In, &At, S8Lit("pairs")); + ConsumeWhiteSpacePastChar(Json.Size, In, &At, ':'); + ConsumeWhiteSpacePastChar(Json.Size, In, &At, '['); + + f64 TotalSum = 0; + umm PairCount = 0; + b32 PairsRemaining = true; + + // One pair + while(PairsRemaining && (At < Json.Size)) + { + ConsumeWhiteSpacePastChar(Json.Size, In, &At, '{'); - umm FileSize = StatBuffer.st_size; - u8 *JsonMemory = (u8 *)mmap(0, FileSize, PROT_READ, MAP_PRIVATE, JsonFile, 0); - AssertErrnoNotEquals((smm)JsonMemory, (smm)MAP_FAILED); + ConsumeHaversineJsonNumber(Json.Size, In, &At, S8Lit("x0"), &X0, true); + ConsumeHaversineJsonNumber(Json.Size, In, &At, S8Lit("y0"), &Y0, true); + ConsumeHaversineJsonNumber(Json.Size, In, &At, S8Lit("x1"), &X1, true); + ConsumeHaversineJsonNumber(Json.Size, In, &At, S8Lit("y1"), &Y1, false); - f64 X0 = 0.0; - f64 X1 = 0.0; - f64 Y0 = 0.0; - f64 Y1 = 0.0; + f64 Sum = ReferenceHaversine(X0, Y0, X1, Y1, 6372.8); + TotalSum += Sum; - // Json Parsing - u8 *In = JsonMemory; + if(Answers.Size) + { + // NOTE(luca): What to do here? + //f64 AnswerSum = ((f64 *)Answers.Data)[AnswerIndex]; + + AnswerIndex += 1; + } - umm At = 0; - ConsumeWhiteSpacePastChar(FileSize, In, &At, '{'); - ConsumePastJsonString(FileSize, In, &At, S8Lit("pairs")); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ':'); - ConsumeWhiteSpacePastChar(FileSize, In, &At, '['); + ConsumeWhiteSpacePastChar(Json.Size, In, &At, '}'); - b32 PairsRemaining = true; - // One pair - while(PairsRemaining && (At < FileSize)) - { - ConsumeWhiteSpacePastChar(FileSize, In, &At, '{'); - - ConsumePastJsonString(FileSize, In, &At, S8Lit("x0")); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ':'); - while(At < FileSize && IsWhiteSpace(In[At])) At += 1; - ParseFloatNumber(FileSize, In, &At, &X0); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ','); - - ConsumePastJsonString(FileSize, In, &At, S8Lit("y0")); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ':'); - while(At < FileSize && IsWhiteSpace(In[At])) At += 1; - ParseFloatNumber(FileSize, In, &At, &Y0); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ','); - - ConsumePastJsonString(FileSize, In, &At, S8Lit("x1")); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ':'); - while(At < FileSize && IsWhiteSpace(In[At])) At += 1; - ParseFloatNumber(FileSize, In, &At, &X1); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ','); - - ConsumePastJsonString(FileSize, In, &At, S8Lit("y1")); - ConsumeWhiteSpacePastChar(FileSize, In, &At, ':'); - while(At < FileSize && IsWhiteSpace(In[At])) At += 1; - ParseFloatNumber(FileSize, In, &At, &Y1); - - LogFormat("X0: %.15f, Y0: %.15f, X1: %.15f, Y1: %.15f\n", X0, Y0, X1, Y1); - - ConsumeWhiteSpacePastChar(FileSize, In, &At, '}'); - - while(At < FileSize && IsWhiteSpace(In[At])) At += 1; - PairsRemaining = (In[At] == '{' || At >= FileSize); + if(At < Json.Size && In[At] == ',') + { + At += 1; } - ConsumeWhiteSpacePastChar(FileSize, In, &At, ']'); - ConsumeWhiteSpacePastChar(FileSize, In, &At, '}'); + while(At < Json.Size && IsWhiteSpace(In[At])) At += 1; + PairsRemaining = (In[At] == '{' || At >= Json.Size); + + PairCount += 1; + } + + ConsumeWhiteSpacePastChar(Json.Size, In, &At, ']'); + ConsumeWhiteSpacePastChar(Json.Size, In, &At, '}'); + + f64 AverageSum = TotalSum / (f64)PairCount; + LogFormat("Input size: %lu\n" + "Pair count: %lu\n" + "Haversine sum: %.16f\n" + , Json.Size, PairCount, AverageSum); + + if(Answers.Size) + { + f64 AnswerAverageSum = ((f64 *)Answers.Data)[AnswerIndex]; + AnswerIndex += 1; + + Assert((AnswerIndex * sizeof(f64)) == Answers.Size); + + LogFormat("\nValidation\n" + "Reference sum: %.16f\n" + "Difference: %.16f\n" + , AnswerAverageSum, AnswerAverageSum - AverageSum); + } |
