2023-06-26 13:51:45 +00:00
# include <stdbool.h>
# include <stdint.h>
# include <stdio.h>
# include <Windows.h>
# include <math.h>
2023-08-24 12:14:24 +00:00
# include "haversine_stdlib.h"
# include "listing_0074_platform_metrics.cpp"
2023-06-30 11:30:31 +00:00
# include "listing_0065_haversine_formula.cpp"
2023-08-24 12:14:24 +00:00
# include "haversine_stdlib.c"
2023-06-26 13:51:45 +00:00
2023-06-30 11:30:31 +00:00
# define PRINT_USAGE HAV_PrintLnFmt("Usage: %s [uniform / cluster] [random seed] [number of coordinate pairs to generate]", argv[0])
2023-06-26 13:51:45 +00:00
int main ( int argc , char * * argv )
{
2024-03-03 11:33:57 +00:00
// NOTE: Unit Tests ////////////////////////////////////////////////////////////////////////////
2023-06-26 13:51:45 +00:00
{
{
2023-06-30 11:30:31 +00:00
HAV_Str8ToU64Result result = HAV_Str8_ToU64 ( HAV_STR8 ( " 00 " ) ) ;
HAV_ASSERT ( result . success ) ;
HAV_ASSERT ( result . value = = 0 ) ;
2023-06-26 13:51:45 +00:00
}
{
2023-06-30 11:30:31 +00:00
HAV_Str8ToU64Result result = HAV_Str8_ToU64 ( HAV_STR8 ( " +100 " ) ) ;
HAV_ASSERT ( ! result . success ) ;
2023-06-26 13:51:45 +00:00
}
{
2023-06-30 11:30:31 +00:00
HAV_Str8ToU64Result result = HAV_Str8_ToU64 ( HAV_STR8 ( " 100,0 " ) ) ;
HAV_ASSERT ( ! result . success ) ;
2023-06-26 13:51:45 +00:00
}
{
2023-06-30 11:30:31 +00:00
HAV_Str8ToU64Result result = HAV_Str8_ToU64 ( HAV_STR8 ( " 100a " ) ) ;
HAV_ASSERT ( ! result . success ) ;
2023-06-26 13:51:45 +00:00
}
{
2023-06-30 11:30:31 +00:00
HAV_Str8ToU64Result result = HAV_Str8_ToU64 ( HAV_STR8 ( " 3147 " ) ) ;
HAV_ASSERT ( result . success ) ;
HAV_ASSERT ( result . value = = 3147 ) ;
2023-06-26 13:51:45 +00:00
}
}
2024-03-03 11:33:57 +00:00
// NOTE: Arg Parsing ///////////////////////////////////////////////////////////////////////////
2023-06-26 13:51:45 +00:00
if ( argc ! = 4 ) {
PRINT_USAGE ;
return - 1 ;
}
2023-06-30 11:30:31 +00:00
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 ] ) } ;
2023-06-26 13:51:45 +00:00
typedef enum PointGenerator {
PointGenerator_Invalid ,
PointGenerator_Uniform ,
PointGenerator_Cluster ,
} PointGenerator ;
2023-06-30 11:30:31 +00:00
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 ) ;
2023-06-26 13:51:45 +00:00
PointGenerator point_generator = PointGenerator_Invalid ;
2023-06-30 11:30:31 +00:00
if ( HAV_Str8_Equals ( arg_uniform_cluster , HAV_STR8 ( " uniform " ) ) ) {
2023-06-26 13:51:45 +00:00
point_generator = PointGenerator_Uniform ;
2023-06-30 11:30:31 +00:00
} else if ( HAV_Str8_Equals ( arg_uniform_cluster , HAV_STR8 ( " cluster " ) ) ) {
2023-06-26 13:51:45 +00:00
point_generator = PointGenerator_Cluster ;
} else {
PRINT_USAGE ;
return - 1 ;
}
if ( ! random_seed_u64_result . success ) {
2023-06-30 11:30:31 +00:00
HAV_PrintLnFmt ( " Random seed was not a valid U64 value [seed=%.*s] " , HAV_STR8_FMT ( arg_random_seed ) ) ;
2023-06-26 13:51:45 +00:00
PRINT_USAGE ;
return - 1 ;
}
if ( ! number_of_coordinate_pairs_to_generate_u64_result . success ) {
2023-06-30 11:30:31 +00:00
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 ) ) ;
2023-06-26 13:51:45 +00:00
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 ) {
2023-06-30 11:30:31 +00:00
HAV_PrintLnFmt ( " Maximum number of coordinate pairs exceeded, exiting to avoid accidental large files [requested=%zu, max=%zu] " ,
2023-06-26 13:51:45 +00:00
number_of_coordinate_pairs_to_generate_u64_result . value ,
MAX_COORD_PAIRS ) ;
PRINT_USAGE ;
return - 1 ;
}
2024-03-03 11:33:57 +00:00
// NOTE: Generator /////////////////////////////////////////////////////////////////////////////
2023-06-26 13:51:45 +00:00
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 ;
2023-07-01 12:32:50 +00:00
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 ) ;
2023-06-26 13:51:45 +00:00
HANDLE haversine_json_file_handle = CreateFile (
2023-07-01 12:32:50 +00:00
/*LPCSTR lpFileName*/ json_file_name ,
2023-06-26 13:51:45 +00:00
/*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 (
2023-07-01 12:32:50 +00:00
/*LPCSTR lpFileName*/ answers_file_name ,
2023-06-26 13:51:45 +00:00
/*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 ;
2023-06-30 11:30:31 +00:00
HAV_PrintHandle ( haversine_json_file_handle , HAV_STR8 ( " { \" pairs \" :[ \n " ) ) ;
2023-06-26 13:51:45 +00:00
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 ) {
2023-06-30 11:30:31 +00:00
point_centre = HAV_PCG32_PieF64 ( & rng_state , LAT_LON_MIN , LAT_LON_MAX ) ;
point_min_offset = - HAV_PCG32_PieF64 ( & rng_state , 0 , 45 ) ;
2023-06-26 13:51:45 +00:00
point_max_offset = - point_min_offset ;
}
2023-06-30 11:30:31 +00:00
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 ) ;
2023-06-26 13:51:45 +00:00
f64 haversine_dist = ReferenceHaversine ( x0 , y0 , x1 , y1 , /*EarthRadius*/ 6372.8 ) ;
2023-06-30 11:30:31 +00:00
HAV_PrintHandle ( haversine_f64_file_handle , ( HAV_Str8 ) { . data = ( char * ) & haversine_dist , . size = sizeof ( haversine_dist ) } ) ;
2023-06-26 13:51:45 +00:00
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 ) ? " " : " , " ) ) ;
2023-06-30 11:30:31 +00:00
HAV_ASSERT ( json_line_size < sizeof ( tmp_buffer ) ) ;
HAV_PrintHandle ( haversine_json_file_handle , ( HAV_Str8 ) { . data = tmp_buffer , . size = json_line_size } ) ;
2023-06-26 13:51:45 +00:00
}
2023-06-30 11:30:31 +00:00
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 ) } ) ;
2023-06-26 13:51:45 +00:00
CloseHandle ( haversine_json_file_handle ) ;
CloseHandle ( haversine_f64_file_handle ) ;
2023-06-30 11:30:31 +00:00
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 ) ;
2023-06-26 13:51:45 +00:00
return 0 ;
}