diff --git a/linear.cpp b/linear.cpp index 063e01c..03f5f40 100644 --- a/linear.cpp +++ b/linear.cpp @@ -6,6 +6,7 @@ #include #include "linear.h" #include "tron.h" +#include int liblinear_version = LIBLINEAR_VERSION; typedef signed char schar; template static inline void swap(T& x, T& y) { T t=x; x=y; y=t; } @@ -45,6 +46,62 @@ static void info(const char *fmt,...) #else static void info(const char *fmt,...) {} #endif + +// New function to ensure the same behaviour for random number generation on windows and linux +inline int myrand() { +// In MS Visual Studio (2012) RAND_MAX = 0x7FFF (15bit) = 32767 +// In Linux GCC (4.6) 32bits RAND_MAX = 0x7FFFFFFF (31bit) = 2147483647 +// In Linux GCC (4.6) 64bits RAND_MAX = 0x7FFFFFFFFFFFFFFF (63 bits) = 9223372036854775807 +// so in MS Visual Studio we need to call rand() several times to always ensure the same random number range than in Linux GCC +#if RAND_MAX != INT_MAX + #if INT_MAX == 0x7FFFFFFF + // make a 31bit random number by using several 15bit rand() + // info("Fixing random number generator for 32 bits ints. RAND_MAX=%d INT_MAX=%d\n", RAND_MAX, INT_MAX); + return ( (__int32)rand() << 16) + ( (__int32)rand() << 1) + ( (__int32)rand() >> 14); + #elif INT_MAX == 0x7FFFFFFFFFFFFFFF + // make a 63bit random number by using several 15bit rand() + // info("Fixing random number generator for 64 bits ints. RAND_MAX=%d INT_MAX=%d\n", RAND_MAX, INT_MAX); + return ( ( (__int64)rand() << 48) + ( (__int64)rand() << 33) + ( (__int64)rand() << 18) + ( (__int64)rand() << 3) + ( (__int64)rand() >> 12) ); + #else + //fallback - should never happen on 32 or 64 bits windows systems + info("Random number generator is not fixed for this system. Please report issue. RAND_MAX=%d INT_MAX=%d\n", RAND_MAX, INT_MAX); + exit(1); + #endif +#else + // In Linux GCC (4.6) 32bits RAND_MAX = 0x7FFFFFFF (31bit) or 64bits RAND_MAX = 0x7FFFFFFFFFFFFFFF (63 bits) + // nothing special to do + return rand(); +#endif +} + +// For auto-check at startup +const char *check_rand_fixed() { + //info("\nMaximum integer value on your system is : %d \n", std::numeric_limits::max()); + int maxRandWindows = 0x7FFF; + int verif; + // perform the same operation than in myrand() +#if RAND_MAX != INT_MAX + #if INT_MAX == 0x7FFFFFFF + verif = ( (__int32)maxRandWindows << 16) + ( (__int32)maxRandWindows << 1) + ( (__int32)maxRandWindows >> 14); + #elif INT_MAX == 0x7FFFFFFFFFFFFFFF + // a priori will never be used as int have the same size on 32 and 64 bit systems + verif = ( (__int64)maxRandWindows << 48) + ( (__int64)maxRandWindows << 33) + ( (__int64)maxRandWindows << 18) + ( (__int64)maxRandWindows << 3) + ( (__int64)maxRandWindows >> 12); + #else + return "This error should never happen - please report\n"; + #endif + if (INT_MAX != verif) { + info("\nMaximum integer value on your system is : %d \n", INT_MAX); + info("Our fix provides a maximum random number value of : %d \n", verif); + return "Random number fix was unable to work for your system/arch"; + } + else { + return NULL; + } +#else + return NULL; +#endif +} + class sparse_operator { public: @@ -625,7 +682,7 @@ void Solver_MCSVM_CS::Solve(double *w) double stopping = -INF; for(i=0;ilabel = NULL; diff --git a/linear.h b/linear.h index 7ad9606..f240ae4 100644 --- a/linear.h +++ b/linear.h @@ -49,6 +49,9 @@ struct model double bias; }; +// new function to check random number generation fix +const char *check_rand_fixed(); + struct model* train(const struct problem *prob, const struct parameter *param); void cross_validation(const struct problem *prob, const struct parameter *param, int nr_fold, double *target); void find_parameters(const struct problem *prob, const struct parameter *param, int nr_fold, double start_C, double start_p, double *best_C, double *best_p, double *best_score); diff --git a/train.c b/train.c index 66f3e4d..824e7ca 100644 --- a/train.c +++ b/train.c @@ -101,6 +101,16 @@ double bias; int main(int argc, char **argv) { + + // Auto-check random number generator fix at startup + const char *error_msg_rand; + error_msg_rand = check_rand_fixed(); + if (error_msg_rand) + { + fprintf(stderr, "ERROR: %s\n", error_msg_rand); + exit(1); + } + char input_file_name[1024]; char model_file_name[1024]; const char *error_msg; diff --git a/windows/liblinear.dll b/windows/liblinear.dll index 6b32017..ac047a4 100755 Binary files a/windows/liblinear.dll and b/windows/liblinear.dll differ diff --git a/windows/libsvmread.mexw64 b/windows/libsvmread.mexw64 index e8f84d9..b95785e 100755 Binary files a/windows/libsvmread.mexw64 and b/windows/libsvmread.mexw64 differ diff --git a/windows/libsvmwrite.mexw64 b/windows/libsvmwrite.mexw64 index f3fd9a9..2f68c28 100755 Binary files a/windows/libsvmwrite.mexw64 and b/windows/libsvmwrite.mexw64 differ diff --git a/windows/predict.exe b/windows/predict.exe index 08fa8e0..0bcbf12 100755 Binary files a/windows/predict.exe and b/windows/predict.exe differ diff --git a/windows/predict.mexw64 b/windows/predict.mexw64 index 7869e93..95ea4c7 100755 Binary files a/windows/predict.mexw64 and b/windows/predict.mexw64 differ diff --git a/windows/train.exe b/windows/train.exe index bd75dec..5466605 100755 Binary files a/windows/train.exe and b/windows/train.exe differ diff --git a/windows/train.mexw64 b/windows/train.mexw64 index a40cb5d..248c2f8 100755 Binary files a/windows/train.mexw64 and b/windows/train.mexw64 differ