172 lines
7.4 KiB
C
172 lines
7.4 KiB
C
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <Windows.h>
|
|
#include <math.h>
|
|
|
|
#include "haversine_stdlib.h"
|
|
#include "listing_0074_platform_metrics.cpp"
|
|
#include "listing_0065_haversine_formula.cpp"
|
|
#include "haversine_stdlib.c"
|
|
|
|
#define PRINT_USAGE HAV_PrintLnFmt("Usage: %s [uniform/cluster] [random seed] [number of coordinate pairs to generate]", argv[0])
|
|
int main(int argc, char **argv)
|
|
{
|
|
// NOTE: Unit Tests ////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
{
|
|
HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("00"));
|
|
HAV_ASSERT(result.success);
|
|
HAV_ASSERT(result.value == 0);
|
|
}
|
|
|
|
{
|
|
HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("+100"));
|
|
HAV_ASSERT(!result.success);
|
|
}
|
|
|
|
{
|
|
HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("100,0"));
|
|
HAV_ASSERT(!result.success);
|
|
}
|
|
|
|
{
|
|
HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("100a"));
|
|
HAV_ASSERT(!result.success);
|
|
}
|
|
|
|
{
|
|
HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("3147"));
|
|
HAV_ASSERT(result.success);
|
|
HAV_ASSERT(result.value == 3147);
|
|
}
|
|
}
|
|
|
|
// NOTE: Arg Parsing ///////////////////////////////////////////////////////////////////////////
|
|
if (argc != 4) {
|
|
PRINT_USAGE;
|
|
return -1;
|
|
}
|
|
|
|
HAV_Str8 arg_uniform_cluster = {argv[1], strlen(argv[1])};
|
|
HAV_Str8 arg_random_seed = {argv[2], strlen(argv[2])};
|
|
HAV_Str8 arg_number_of_coordinate_pairs_to_generate = {argv[3], strlen(argv[3])};
|
|
|
|
typedef enum PointGenerator {
|
|
PointGenerator_Invalid,
|
|
PointGenerator_Uniform,
|
|
PointGenerator_Cluster,
|
|
} PointGenerator;
|
|
|
|
HAV_Str8ToU64Result random_seed_u64_result = HAV_Str8_ToU64(arg_random_seed);
|
|
HAV_Str8ToU64Result number_of_coordinate_pairs_to_generate_u64_result = HAV_Str8_ToU64(arg_number_of_coordinate_pairs_to_generate);
|
|
PointGenerator point_generator = PointGenerator_Invalid;
|
|
|
|
if (HAV_Str8_Equals(arg_uniform_cluster, HAV_STR8("uniform"))) {
|
|
point_generator = PointGenerator_Uniform;
|
|
} else if (HAV_Str8_Equals(arg_uniform_cluster, HAV_STR8("cluster"))) {
|
|
point_generator = PointGenerator_Cluster;
|
|
} else {
|
|
PRINT_USAGE;
|
|
return -1;
|
|
}
|
|
|
|
if (!random_seed_u64_result.success) {
|
|
HAV_PrintLnFmt("Random seed was not a valid U64 value [seed=%.*s]", HAV_STR8_FMT(arg_random_seed));
|
|
PRINT_USAGE;
|
|
return -1;
|
|
}
|
|
|
|
if (!number_of_coordinate_pairs_to_generate_u64_result.success) {
|
|
HAV_PrintLnFmt("Number of coordinate pairs to generate was not a valid U64 value [seed=%.*s]", HAV_STR8_FMT(arg_number_of_coordinate_pairs_to_generate));
|
|
PRINT_USAGE;
|
|
return -1;
|
|
}
|
|
|
|
uint32_t const MAX_COORD_PAIRS = 100'000'000;
|
|
if (number_of_coordinate_pairs_to_generate_u64_result.value > MAX_COORD_PAIRS) {
|
|
HAV_PrintLnFmt("Maximum number of coordinate pairs exceeded, exiting to avoid accidental large files [requested=%zu, max=%zu]",
|
|
number_of_coordinate_pairs_to_generate_u64_result.value,
|
|
MAX_COORD_PAIRS);
|
|
PRINT_USAGE;
|
|
return -1;
|
|
}
|
|
|
|
// NOTE: Generator /////////////////////////////////////////////////////////////////////////////
|
|
uint64_t point_count = number_of_coordinate_pairs_to_generate_u64_result.value;
|
|
uint64_t random_seed = random_seed_u64_result.value;
|
|
uint64_t rng_state = random_seed;
|
|
|
|
char json_file_name[1024];
|
|
char answers_file_name[1024];
|
|
snprintf(json_file_name, sizeof(json_file_name), "haversine_%zu_%s_%zu.json", point_count, point_generator == PointGenerator_Cluster ? "cluster" : "uniform", random_seed);
|
|
snprintf(answers_file_name, sizeof(json_file_name), "haversine_%zu_%s_%zu.f64", point_count, point_generator == PointGenerator_Cluster ? "cluster" : "uniform", random_seed);
|
|
|
|
HANDLE haversine_json_file_handle = CreateFile(
|
|
/*LPCSTR lpFileName*/ json_file_name,
|
|
/*DWORD dwDesiredAccess*/ GENERIC_WRITE,
|
|
/*DWORD dwShareMode*/ 0,
|
|
/*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ NULL,
|
|
/*DWORD dwCreationDisposition*/ CREATE_ALWAYS,
|
|
/*DWORD dwFlagsAndAttributes*/ 0,
|
|
/*HANDLE hTemplateFile*/ NULL
|
|
);
|
|
|
|
HANDLE haversine_f64_file_handle = CreateFile(
|
|
/*LPCSTR lpFileName*/ answers_file_name,
|
|
/*DWORD dwDesiredAccess*/ GENERIC_WRITE,
|
|
/*DWORD dwShareMode*/ 0,
|
|
/*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ NULL,
|
|
/*DWORD dwCreationDisposition*/ CREATE_ALWAYS,
|
|
/*DWORD dwFlagsAndAttributes*/ 0,
|
|
/*HANDLE hTemplateFile*/ NULL
|
|
);
|
|
|
|
f64 const LAT_LON_MIN = -180.0;
|
|
f64 const LAT_LON_MAX = 180.0;
|
|
|
|
uint64_t const MAX_CLUSTERS = 64;
|
|
uint64_t const points_per_cluster = point_count / MAX_CLUSTERS;
|
|
|
|
char tmp_buffer[128];
|
|
f64 expected_sum = 0;
|
|
HAV_PrintHandle(haversine_json_file_handle, HAV_STR8("{\"pairs\":[\n"));
|
|
|
|
f64 const sum_coefficient = 1.0 / point_count;
|
|
f64 point_centre = 0;
|
|
f64 point_min_offset = LAT_LON_MIN;
|
|
f64 point_max_offset = LAT_LON_MAX;
|
|
for (int index = 0; index < point_count; index++) {
|
|
if (point_generator == PointGenerator_Cluster && (index % points_per_cluster) == 0) {
|
|
point_centre = HAV_PCG32_PieF64(&rng_state, LAT_LON_MIN, LAT_LON_MAX);
|
|
point_min_offset = -HAV_PCG32_PieF64(&rng_state, 0, 45);
|
|
point_max_offset = -point_min_offset;
|
|
}
|
|
|
|
f64 x0 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset);
|
|
f64 y0 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset);
|
|
f64 x1 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset);
|
|
f64 y1 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset);
|
|
|
|
f64 haversine_dist = ReferenceHaversine(x0, y0, x1, y1, /*EarthRadius*/ 6372.8);
|
|
HAV_PrintHandle(haversine_f64_file_handle, (HAV_Str8){.data = (char *)&haversine_dist, .size = sizeof(haversine_dist)});
|
|
expected_sum += (sum_coefficient * haversine_dist);
|
|
|
|
size_t json_line_size = snprintf(tmp_buffer, sizeof(tmp_buffer), " {\"x0\": %f, \"y0\": %f, \"x1\": %f, \"y1\": %f}%s\n", x0, y0, x1, y1, (index == (point_count - 1) ? "" : ","));
|
|
HAV_ASSERT(json_line_size < sizeof(tmp_buffer));
|
|
HAV_PrintHandle(haversine_json_file_handle, (HAV_Str8){.data = tmp_buffer, .size = json_line_size});
|
|
}
|
|
HAV_PrintHandle(haversine_json_file_handle, HAV_STR8("]}\n"));
|
|
HAV_PrintHandle(haversine_f64_file_handle, (HAV_Str8){.data = (char *)&expected_sum, .size = sizeof(expected_sum)});
|
|
|
|
CloseHandle(haversine_json_file_handle);
|
|
CloseHandle(haversine_f64_file_handle);
|
|
|
|
HAV_PrintLnFmt("Method: %s", (point_generator == PointGenerator_Uniform ? "uniform" : "cluster"));
|
|
HAV_PrintLnFmt("Seed: %zu", random_seed);
|
|
HAV_PrintLnFmt("Pair Count: %zu", point_count);
|
|
HAV_PrintLnFmt("Expected Sum: %f", expected_sum);
|
|
return 0;
|
|
}
|