[ create a new paste ] login | about

Link: http://codepad.org/P6Os5MKf    [ raw code | fork ]

C++, pasted on Nov 28:
#define _SECURE_SCL 0
#define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE

#include <iostream>
#include <sstream>
#include <string>
#include <boost/range/iterator_range.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/chrono.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <cmath>
#include <cstdlib>

using namespace std;
using namespace boost;
using namespace boost::chrono;
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;

int parse_int(const string& valueStr)
{
    int result;
    qi::parse(valueStr.begin(), valueStr.end(), qi::int_, result);
    return result;
}

double parse_double(const string& valueStr)
{
    double result;
    qi::parse(valueStr.begin(), valueStr.end(), qi::double_, result);
    return result;
}

template <typename T> T tabs(T x) {return x < 0 ? -x : x;}

bool AlmostEqual2sComplement(double A, double B, int maxUlps)
{
    // Make sure maxUlps is non-negative and small enough that the
    // default NAN won't compare as equal to anything.
    assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);

    int64_t aInt = *(int64_t*)&A;
    // Make aInt lexicographically ordered as a twos-complement int
    if (aInt < 0)
        aInt = 0x8000000000000000 - aInt;

    // Make bInt lexicographically ordered as a twos-complement int
    int64_t bInt = *(int64_t*)&B;
    if (bInt < 0)
        bInt = 0x8000000000000000 - bInt;

    int64_t intDiff = tabs(aInt - bInt);
    if (intDiff <= maxUlps)
        return true;
    return false;
}

template<typename T>
bool test(T value, const std::string& valueStr)
{
    typedef steady_clock test_clock;
    test_clock::time_point start, stop;
    const int iterations = 1000000;

    cout << endl << iterations << " iterations of \"" << valueStr << "\":" << endl;

    bool isInteger = (double) atoi(valueStr.c_str()) == (double) value;

    if (isInteger)
    {
        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
            if (atoi(valueStr.c_str()) != value)
                return false;
        stop = test_clock::now();
        cout << "atoi: " << duration<double>(stop - start) << endl;

        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
        {
		    const char* stringToConvert = valueStr.c_str();
		    const char* endOfConversion = stringToConvert;
		    long value2 = strtol(stringToConvert, const_cast<char**>(&endOfConversion), 10);
		    if (value2 == 0.0 && stringToConvert == endOfConversion) // error: conversion could not be performed
			    throw bad_lexical_cast();
            if (value2 != (long) value)
                return false;
        }
        stop = test_clock::now();
        cout << "strtol: " << duration<double>(stop - start) << endl;

        long scanValue;
        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
        {
            sscanf(valueStr.c_str(), "%ld", &scanValue);
            if (scanValue != value)
                return false;
        }
        stop = test_clock::now();
        cout << "sscanf: " << duration<double>(stop - start) << endl;

        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
            if (parse_int(valueStr) != value)
                return false;
        stop = test_clock::now();
        cout << "Spirit: " << duration<double>(stop - start) << endl;
    }
    else
    {
        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
            if (!AlmostEqual2sComplement(atof(valueStr.c_str()), value, 1))
                return false;
        stop = test_clock::now();
        cout << "atof: " << duration<double>(stop - start) << endl;

        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
        {
		    const char* stringToConvert = valueStr.c_str();
		    const char* endOfConversion = stringToConvert;
		    double value2 = strtod( stringToConvert, const_cast<char**>(&endOfConversion) );
		    if (value2 == 0.0 && stringToConvert == endOfConversion) // error: conversion could not be performed
			    throw bad_lexical_cast();
            if (!AlmostEqual2sComplement(value2, value, 1))
                return false;
        }
        stop = test_clock::now();
        cout << "strtod: " << duration<double>(stop - start) << endl;
        
        double scanValue;
        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
        {
            sscanf(valueStr.c_str(), "%lf", &scanValue);
            if (!AlmostEqual2sComplement(scanValue, value, 1))
                return false;
        }
        stop = test_clock::now();
        cout << "sscanf: " << duration<double>(stop - start) << endl;

        start = test_clock::now();
        for (int i=0; i < iterations; ++i)
            if (!AlmostEqual2sComplement(parse_double(valueStr), value, 1))
                return false;
        stop = test_clock::now();
        cout << "Spirit: " << duration<double>(stop - start) << endl;
    }

    start = test_clock::now();
    for (int i=0; i < iterations; ++i)
        if (lexical_cast<T>(valueStr) != value)
            return false;
    stop = test_clock::now();
    cout << "lexical_cast(string): " << duration<double>(stop - start) << endl;

    iterator_range<string::const_iterator> valueRng = make_iterator_range(valueStr.begin(), valueStr.end());
    start = test_clock::now();
    for (int i=0; i < iterations; ++i)
        if (lexical_cast<T>(valueRng) != value)
            return false;
    stop = test_clock::now();
    cout << "lexical_cast(iterator_range): " << duration<double>(stop - start) << endl;

    start = test_clock::now();
    for (int i=0; i < iterations; ++i)
        if (lexical_cast<T>(string(valueRng.begin(), valueRng.end())) != value)
            return false;
    stop = test_clock::now();
    cout << "lexical_cast(iterator_range->string): " << duration<double>(stop - start) << endl;

    return true;
}

int main()
{
    test(123, "123");
    test(123567890, "123567890");
    test(1.23456, "1.23456");
    test(1.23456789e42, "1.23456789e42");
    return 0;
}


Create a new paste based on this one


Comments: