Skip to main content
deleted 658 characters in body
Source Link
Arnoud Buzing
  • 9.9k
  • 2
  • 50
  • 58

Noteupdated based on comment feedback: Some (most?) compilers expect two argument versions for the strtol and strtod. The code below was written on a Windows system which prefers three arguments (including a base argument). link

One more approach, using LibraryLink. Create a C file called strto.ccpp as follows:

#include <stdlib.h> #include <stdio.h><cstdlib> #include "WolframLibrary.h" EXTERN_C DLLEXPORT int wolfram_strtol(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mint result; string = MArgument_getUTF8String(Args[0]); base = MArgument_getInteger(Args[1]); result = strtol(string, NULL, base); MArgument_setInteger(Res,result); return LIBRARY_NO_ERROR; } EXTERN_C DLLEXPORT int wolfram_strtod(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mreal result; string = MArgument_getUTF8String(Args[0]); base = MArgument_getInteger(Args[1]); result = strtod(string, NULL, base); MArgument_setReal(Res,result); return LIBRARY_NO_ERROR; } 

This is a very thin wrapper for the CC++ strtol and strtod standard library functions.

Needs["CCompilerDriver`"]; lib = CreateLibrary[{"wolfram_strto.c"cpp"}, "wolfram_strto"] 
strtol = LibraryFunctionLoad[lib, "wolfram_strtol", {"UTF8String", Integer}, Integer]; strtod = LibraryFunctionLoad[lib, "wolfram_strtod", {"UTF8String", Integer}, Real]; 
strtod["10e4", 10]strtod["10e4"] 
strtod[#, 0] &strtod /@ {"3.14159", "3.14159e-02", "3.14159e+02", "1.23e-5", "1E6", "1.734E-003", "2.12e1"} 

The second argument '0' to strtod signifies automatic base detection.

This should return 10995 (e.g. same as 16^^2AF3)

One benefit strtod has over Internal`StringToDouble is that the latter can not do hexadecimal numbers:

Internal`StringToDouble["0x6400"] 

This returns 6400, which is the (wrong) decimal interpretation.

strings = ToString @ Row[ RandomChoice /@ {{"-", ""}, {#}, {"e"}, {"-", ""}, Range@12}] & /@ RandomReal[{0, 10}, 15000] First@AbsoluteTiming[strtod[#, 0]First@AbsoluteTiming[ &strtod /@ strings] 
Internal`StringToDouble["1e4000"] strtod["1e4000", 0]strtod["1e4000"] 

Note: Some (most?) compilers expect two argument versions for the strtol and strtod. The code below was written on a Windows system which prefers three arguments (including a base argument). link

One more approach, using LibraryLink. Create a C file called strto.c as follows:

#include <stdlib.h> #include <stdio.h> #include "WolframLibrary.h" DLLEXPORT int wolfram_strtol(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mint result; string = MArgument_getUTF8String(Args[0]); base = MArgument_getInteger(Args[1]); result = strtol(string, NULL, base); MArgument_setInteger(Res,result); return LIBRARY_NO_ERROR; } DLLEXPORT int wolfram_strtod(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mreal result; string = MArgument_getUTF8String(Args[0]); base = MArgument_getInteger(Args[1]); result = strtod(string, NULL, base); MArgument_setReal(Res,result); return LIBRARY_NO_ERROR; } 

This is a very thin wrapper for the C strtol and strtod standard library functions.

Needs["CCompilerDriver`"]; lib = CreateLibrary[{"wolfram_strto.c"}, "wolfram_strto"] 
strtol = LibraryFunctionLoad[lib, "wolfram_strtol", {"UTF8String", Integer}, Integer]; strtod = LibraryFunctionLoad[lib, "wolfram_strtod", {"UTF8String", Integer}, Real]; 
strtod["10e4", 10] 
strtod[#, 0] & /@ {"3.14159", "3.14159e-02", "3.14159e+02", "1.23e-5", "1E6", "1.734E-003", "2.12e1"} 

The second argument '0' to strtod signifies automatic base detection.

This should return 10995 (e.g. same as 16^^2AF3)

One benefit strtod has over Internal`StringToDouble is that the latter can not do hexadecimal numbers:

Internal`StringToDouble["0x6400"] 

This returns 6400, which is the (wrong) decimal interpretation.

strings = ToString @ Row[ RandomChoice /@ {{"-", ""}, {#}, {"e"}, {"-", ""}, Range@12}] & /@ RandomReal[{0, 10}, 15000] First@AbsoluteTiming[strtod[#, 0] & /@ strings] 
Internal`StringToDouble["1e4000"] strtod["1e4000", 0] 

updated based on comment feedback

One more approach, using LibraryLink. Create a C file called strto.cpp as follows:

#include <cstdlib> #include "WolframLibrary.h" EXTERN_C DLLEXPORT int wolfram_strtol(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mint result; string = MArgument_getUTF8String(Args[0]); base = MArgument_getInteger(Args[1]); result = strtol(string, NULL,base); MArgument_setInteger(Res,result); return LIBRARY_NO_ERROR; } EXTERN_C DLLEXPORT int wolfram_strtod(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mreal result; string = MArgument_getUTF8String(Args[0]); result = strtod(string, NULL); MArgument_setReal(Res,result); return LIBRARY_NO_ERROR; } 

This is a very thin wrapper for the C++ strtol and strtod standard library functions.

Needs["CCompilerDriver`"]; lib = CreateLibrary[{"wolfram_strto.cpp"}, "wolfram_strto"] 
strtol = LibraryFunctionLoad[lib, "wolfram_strtol", {"UTF8String", Integer}, Integer]; strtod = LibraryFunctionLoad[lib, "wolfram_strtod", {"UTF8String"}, Real]; 
strtod["10e4"] 
strtod /@ {"3.14159", "3.14159e-02", "3.14159e+02", "1.23e-5", "1E6", "1.734E-003", "2.12e1"} 

This should return 10995 (e.g. same as 16^^2AF3)

strings = ToString @ Row[ RandomChoice /@ {{"-", ""}, {#}, {"e"}, {"-", ""}, Range@12}] & /@ RandomReal[{0, 10}, 15000] First@AbsoluteTiming[ strtod /@ strings] 
Internal`StringToDouble["1e4000"] strtod["1e4000"] 
added 320 characters in body
Source Link
Arnoud Buzing
  • 9.9k
  • 2
  • 50
  • 58

Note: Some (most?) compilers expect two argument versions for the strtol and strtod. The code below was written on a Windows system which prefers three arguments (including a base argument). link

One more approach, using LibraryLink. Create a C file called strto.c as follows:

One more approach, using LibraryLink. Create a C file called strto.c as follows:

Note: Some (most?) compilers expect two argument versions for the strtol and strtod. The code below was written on a Windows system which prefers three arguments (including a base argument). link

One more approach, using LibraryLink. Create a C file called strto.c as follows:

Source Link
Arnoud Buzing
  • 9.9k
  • 2
  • 50
  • 58

One more approach, using LibraryLink. Create a C file called strto.c as follows:

#include <stdlib.h> #include <stdio.h> #include "WolframLibrary.h" DLLEXPORT int wolfram_strtol(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mint result; string = MArgument_getUTF8String(Args[0]); base = MArgument_getInteger(Args[1]); result = strtol(string, NULL, base); MArgument_setInteger(Res,result); return LIBRARY_NO_ERROR; } DLLEXPORT int wolfram_strtod(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) { char *string; mint base; mreal result; string = MArgument_getUTF8String(Args[0]); base = MArgument_getInteger(Args[1]); result = strtod(string, NULL, base); MArgument_setReal(Res,result); return LIBRARY_NO_ERROR; } 

This is a very thin wrapper for the C strtol and strtod standard library functions.

Create the library:

Needs["CCompilerDriver`"]; lib = CreateLibrary[{"wolfram_strto.c"}, "wolfram_strto"] 

Load the two library functions:

strtol = LibraryFunctionLoad[lib, "wolfram_strtol", {"UTF8String", Integer}, Integer]; strtod = LibraryFunctionLoad[lib, "wolfram_strtod", {"UTF8String", Integer}, Real]; 

Test the basics:

strtol["104", 10] 

This should return the integer 104

strtod["10e4", 10] 

This should return the real 100000.

Check some harder cases:

strtod[#, 0] & /@ {"3.14159", "3.14159e-02", "3.14159e+02", "1.23e-5", "1E6", "1.734E-003", "2.12e1"} 

The second argument '0' to strtod signifies automatic base detection.

Try a hex number:

strtol["0x2AF3", 0] 

This should return 10995 (e.g. same as 16^^2AF3)

One benefit strtod has over Internal`StringToDouble is that the latter can not do hexadecimal numbers:

Internal`StringToDouble["0x6400"] 

This returns 6400, which is the (wrong) decimal interpretation.

Measure the elapsed time to 15,000 randomly generated reals:

strings = ToString @ Row[ RandomChoice /@ {{"-", ""}, {#}, {"e"}, {"-", ""}, Range@12}] & /@ RandomReal[{0, 10}, 15000] First@AbsoluteTiming[strtod[#, 0] & /@ strings] 

Returns in about 0.017 seconds on my machine.

For big numbers, there is another difference:

Internal`StringToDouble["1e4000"] strtod["1e4000", 0] 

The StringToDouble function gives $Failed["IEEE Exception"] and the strtod function gives DirectedInfinity[1].

In the case of underflow you get, respectively, $Failed["IEEE Underflow"] and 0.

Also, StringToDouble recognizes WL notation (e.g. 6.022*^23) and strtod does not recognize this format.