Mathematical Expression Showdown!

15

1

You are given 6 numbers: 5 digits [0-9] and a target number. Your goal is to intersperse operators between the digits to get as close as you can to the target. You have to use each digit exactly once, and can use the following operators as many times as you want: + - * / () ^ sqrt sin cos tan. For example, if I'm given 8 2 4 7 2 65 I can output 82-(2*7)-4. This evaluates to 64, thus giving me a score of 1 since I was 1 away from the target. Note: You can not put a decimal point between digits.

I am using the code from this StackOverflow answer to evaluate the mathematical expressions. At the bottom of this question there are programs you can use to test it out.

Chaining Functions (Update!)

@mdahmoune has revealed a new level of complexity to this challenge. As such, I'm adding a new feature: chaining unary functions. This works on sin, cos, tan, and sqrt. Now instead of writing sin(sin(sin(sin(10)))), you can write sin_4(10). Try it out in the evaluator!

Input

200 line-separated test cases of 5 digits and a target number that are space-separated. You can use the program at the bottom of the question to make sample test cases, but I will have my own test cases for official scoring. The test cases are broken up into 5 sections of 40 tests with the following ranges for the target number:

  • Section 1: [0,1] (to 5 decimal points)
  • Section 2: [0,10] (to 4 decimal points)
  • Section 3: [0,1000] (to 3 decimal points)
  • Section 4: [0,106] (to 1 decimal point)
  • Section 5: [0,109] (to 0 decimal points)

Output

200 line separated mathematical expressions. For example, if the test case is 5 6 7 8 9 25.807, a possible output could be 78-59+6

Scoring

The goal each round is to get closer to the target number than the other competing programs. I'm going to use Mario Kart 8 scoring, which is: 1st: 15 2nd: 12 3rd: 10 4th: 9 5th: 8 6th: 7 7th: 6 8th: 5 9th: 4 10th: 3 11th: 2 12th: 1 13th+: 0. If multiple answers get the same exact score, the points are split evenly, rounded to the nearest int. For example, if the programs in 5th-8th place are tied, they each get (8+7+6+5)/4 = 6.5 => 7 points that round. At the end of 200 rounds, the program that got the most points wins. If two programs have the same number of points at the end, the tie-breaker is the program that finished running faster.

Rules

  1. You can only use one of the languages commonly pre-installed on Mac like C, C++, Java, PhP, Perl, Python (2 or 3), Ruby, and Swift. If you have a language you want to use with a compiler/interpreter that is a relatively small download I may add it. You can also use a language with an online interpreter, but that will not run as fast.
  2. Specify in your answer if you want trig functions to be calculated in degrees or radians.
  3. Your program must output its solutions to all 200 test cases (to a file or STDOUT) within 60 seconds on my Mac.
  4. Randomness must be seeded.
  5. Your total output for all test cases can't be more than 1 MB.
  6. If you have improved your solution and would like to be re-scored, add Re-Score at the top of your answer in bold.

Programs

(change the "deg" argument to "rad" if you want radians)

  1. Test out evaluator
  2. Score your program's output for test cases
  3. Generate test cases:

document.getElementById("but").onclick = gen;
var checks = document.getElementById("checks");
for(var i = 1;i<=6;i++) {
var val = i<6 ? i : "All";
var l = document.createElement("label");
l.for = "check" + val;
l.innerText = " "+val+" ";
checks.appendChild(l);
  var check = document.createElement("input");
  check.type = "checkBox";
  check.id = "check"+val;
  if(val == "All") {
  check.onchange = function() {
  if(this.checked == true)  {
  for(var i = 0;i<5;i++) {
    this.parentNode.elements[i].checked = true;
  }
  }
};  
  }
  else {
  check.onchange = function() {
    document.getElementById("checkAll").checked = false;
  }
  }
  checks.appendChild(check);
  
}



function gen() {
var tests = [];
var boxes = checks.elements;
if(boxes[0].checked)genTests(tests,1,5,40);
if(boxes[1].checked)genTests(tests,10,4,40);
if(boxes[2].checked)genTests(tests,1000,3,40);
if(boxes[3].checked)genTests(tests,1e6,1,40);
if(boxes[4].checked)genTests(tests,1e9,0,40);
document.getElementById("box").value =  tests.join("\n");
}

function genTests(testArray,tMax,tDec,n) {
for(var i = 0;i<n;i++) {
  testArray.push(genNums(tMax,tDec).join(" "));
}
}

function genNums(tMax,tDec) {
var nums = genDigits();
nums.push(genTarget(tMax,tDec));
return nums;
}

function genTarget(tMax,tDec) {
  return genRand(tMax,tDec);
}

function genRand(limit,decimals) {
  var r = Math.random()*limit;
  return r.toFixed(decimals);
}

function genDigits() {
  var digits = [];
   for(var i = 0;i<5;i++) {
    digits.push(Math.floor(Math.random()*10));
   }
   return digits;
}
textarea {
  font-size: 14pt;
  font-family: "Courier New", "Lucida Console", monospace;
}

div {
text-align: center;
}
<div>
<label for="checks">Sections: </label><form id="checks"></form>
<input type="button" id="but" value="Generate Test Cases" /><br/><textarea id="box" cols=20 rows=15></textarea>
</div>

Leaderboard

  1. user202729 (C++): 2856, 152 wins
  2. mdahmoune (Python 2) [v2]: 2544, 48 wins

Section scores (# of wins):

  1. [0-1] user202729: 40, mdahmoune: 0
  2. [0-10] user202729: 40, mdahmoune: 0
  3. [0-1000] user202729: 39, mdahmoune: 1
  4. [0-106] user202729: 33, mdahmoune: 7
  5. [0-109] user202729:0, mdahmoune: 40

Related: Generate a valid equation using user-specified numbers

geokavel

Posted 2017-08-20T15:07:13.577

Reputation: 6 352

Is there any specific reason the trigonometric functions have to use degrees? Could an option possibly be added for the answer to specify either radians or degrees? – notjagan – 2017-08-20T23:16:08.873

Does the set of digits contain necessarily a non zero digit? – mdahmoune – 2017-08-21T15:13:04.150

@mdahmoune The test cases are randomly generated, so the digits could be all 0. You'd just have to do your best in that situation. In degree mode I was able to get all the way up to 3283.14 with cos(0)/sin(0^0)/sin(0^0). – geokavel – 2017-08-21T15:28:43.870

Thanx for your complete answer :) – mdahmoune – 2017-08-21T16:12:58.217

Is it the same scoring method for the 5 different sections? Abs(target_value-generated_expression_value)? I – mdahmoune – 2017-08-22T11:17:46.350

@mda It is, but you have to remember that the number of points you get is based on how your program scores compared to the other programs. – geokavel – 2017-08-22T13:49:24.590

@geokavel The probability of at least 1 test case is all zero is actually 2‰. We can make the output arbitrarily long such that it output in time, correct? – user202729 – 2017-08-23T05:26:52.410

@user202729 Do you mean outputting all the answers at the very end? Yeah, that works. – geokavel – 2017-08-23T14:43:10.660

Is the concatenation considered as an operation? I means, for example for 8 2 4 7 2 : 65 can I produce 65 by concatenating the result of (8+2-4)=6 and (7-2)=5? – mdahmoune – 2017-08-23T15:26:30.080

@mda No, it's not allowed. You can use program 1 to test out what's allowed. – geokavel – 2017-08-23T15:29:09.750

@geokavel With the new evaluator the time limit is evaluate + compute <= 1 min or evaluate <= 1 min, compute <= 1 min? – user202729 – 2017-08-25T08:09:53.820

@geokavel So each test case is a round (independent of each other?) – user202729 – 2017-08-25T14:23:52.410

@user202729 Sorry, I think I mis-answered one of your previous questions. The 60s time limit is just for producing the outputs, not evaluating them. – geokavel – 2017-08-25T14:50:08.067

Is it possible to give the number of cores in your test cpu machine? – mdahmoune – 2017-08-28T10:04:47.360

@mdahmoune Yeah, two. – geokavel – 2017-08-28T14:57:02.200

@mdahmoune , geokavel Unfortunately, despite the bounty, no one had a better answer than mine yet. Anyone consider writing one? – user202729 – 2017-08-29T16:06:52.263

@user202729, geokavel Yes, I'm working on a second draft version.. – mdahmoune – 2017-08-29T16:09:07.690

Perhaps merge the two solutions :D – mdahmoune – 2017-08-29T21:11:51.733

@user202729 feel free to use my function's solution to improve yours – mdahmoune – 2017-08-29T21:25:16.903

@mdahmoune I think using other's idea is cheating. – user202729 – 2017-08-30T05:46:17.820

I reimplemented the evaluator here (TIO link) in C++, but it gives different result for that test case to your Java evaluator. So my score may be worse if the Java evaluator is used. Even on different computers the C++ evaluator return different results.

– user202729 – 2017-09-01T01:59:10.910

@user202729 On the TIO version of the Java evaluator I get 0.999999 for that input. However, on the version of the Java evaluator on my computer I get almost the same answer as your TIO C++ link. So I think you're good. – geokavel – 2017-09-01T03:44:19.553

On the TIO Java I get 6.06058941675148E8 , while on TIO C++ I get 606058696.99925720691681, which have difference of about 1000. How can you get 0.999999? (remember to use rad) Because now mdahmoune 's score is ~ 1e-4 now the precision is very important. How about rescore both answer with the C++ evaluator? – user202729 – 2017-09-01T04:06:22.473

@user202729 The difference is only 245. Yes I forgot to change to rad. How do I know whether Java or C++ version is more accurate? Especially since C++ evaluator returns different results on different computers. – geokavel – 2017-09-01T04:11:58.307

@user202729 I'll try to run both with C++ evaluator, but I'm not really skilled with C++ so it might take me a little bit. – geokavel – 2017-09-01T04:14:01.153

Who knows? (we can try evaluate both on Mathematica with a lot of digits of precision) Does Java evaluator returns different results on different computers? – user202729 – 2017-09-01T04:15:28.507

@user202729 I get same exact result on TIO as on my computer for Java version. – geokavel – 2017-09-01T04:19:05.047

@user202729 I get 606058289.20654487609863 when I run C++ version on my computer, compiled with clang. – geokavel – 2017-09-01T04:30:22.407

TIO get 606058696.999... and I (gcc) get exactly 606058697. I think I will move to Java for accuracy. – user202729 – 2017-09-01T04:32:45.833

Answers

3

C++

// This program use radian mode

//#define DEBUG

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#include <cassert>
#else
#define assert(x) void(0)
#endif

namespace std {
    /// Used for un-debug.
    struct not_cerr_t {
    } not_cerr;
}

template <typename T>
std::not_cerr_t& operator<<(std::not_cerr_t& not_cerr, T) {return not_cerr;}

#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
#include <array>
#include <bitset>
#include <string>
#include <sstream>

#ifndef DEBUG
#define cerr not_cerr
#endif // DEBUG


// String conversion functions, because of some issues with MinGW
template <typename T>
T from_string(std::string st) {
    std::stringstream sst (st);
    T result;
    sst >> result;
    return result;
}

template <typename T>
std::string to_string(T x) {
    std::stringstream sst;
    sst << x;
    return sst.str();
}

template <typename T> int sgn(T val) {
    return (T(0) < val) - (val < T(0));
}


const int N_ITER = 1000, N_DIGIT = 5, NSOL = 4;
std::array<int, N_DIGIT> digits;
double target;

typedef std::bitset<N_ITER> stfunc; // sin-tan expression
// where sin = 0, tan = 1

double eval(const stfunc& fn, int length, double value) {
    while (length --> 0) {
        value = fn[length] ? std::tan(value) : std::sin(value);
    }
    return value;
}

struct stexpr { // just a stfunc with some information
    double x = 0, val = 0; // fn<length>(x) == val
    int length = 0;
    stfunc fn {};
//    bool operator[] (const int x) {return fn[x];}
    double eval() {return val = ::eval(fn, length, x);}
};

struct expr { // general form of stexpr
    // note that expr must be *always* atomic.
    double val = 0;
    std::string expr {};

    void clear() {
        val = 0;
        expr.clear();
    }

    // cos(cos(x)) is in approx 0.5 - 1,
    // so we can expect that sin(x) and tan(x) behaves reasonably nice
    private: void wrapcos2() {
        expr = "(cos_2 " + expr + ")"; // we assume that all expr is atomic
        val = std::cos(std::cos(val));
    }

    public: void wrap1() {
        if (val == 0) {
            expr = "(cos " + expr + ")"; // we assume that all expr is atomic
            val = std::cos(val);
        }
        if (val == 1) return;
        wrapcos2(); // range 0.54 - 1
        int cnt_sqrt = 0;
        for (int i = 0; i < 100; ++i) {
            ++cnt_sqrt;
            val = std::sqrt(val);
            if (val == 1) break;
        }
        expr = "(sqrt_" + to_string(cnt_sqrt) + " " + expr + ")"; // expr must be atomic
    }
};

stexpr nearest(double initial, double target) {
    stexpr result; // built on the fn of that
    result.x = initial;
    double value [N_ITER + 1];
    value[0] = initial;
    for (result.length = 1; result.length <= N_ITER; ++result.length) {
        double x = value[result.length-1];
        if (x < target) {
            result.fn[result.length-1] = 1;
        } else if (x > target) {
            result.fn[result.length-1] = 0;
        } else { // unlikely
            --result.length;
//            result.val = x;
            result.eval();
            assert(result.val == x);
            return result;
        }
        value[result.length] = result.eval(); // this line takes most of the time
        if (value[result.length] == value[result.length-1])
            break;
    }

//    for (int i = 0; i < N_ITER; ++i) {
//        std::cerr << i << '\t' << value[i] << '\t' << (value[i] - target) << '\n';
//    }

    double mindiff = std::numeric_limits<double>::max();
    int resultlength = -1;
    result.length = std::min(N_ITER, result.length);
    for (int l = 0; l <= result.length; ++l) {
        if (std::abs(value[l] - target) < mindiff) {
            mindiff = std::abs(value[l] - target);
            resultlength = l;
        }
    }

    result.length = resultlength;
    double val = value[resultlength];
    assert(std::abs(val - target) == mindiff);
    if (val != target) { // second-order optimization
        for (int i = 1; i < result.length; ++i) {
            // consider pair (i-1, i)
            if (result.fn[i-1] == result.fn[i]) continue; // look for (sin tan) or (tan sin)
            if (val < target && result.fn[i-1] == 0) { // we need to increase val : sin tan -> tan sin
                result.fn[i-1] = 1;
                result.fn[i] = 0;
                double newvalue = result.eval();
//                if (!(newvalue >= val)) std::cerr << "Floating point sin-tan error 1\n";
                if (std::abs(newvalue - target) < std::abs(val - target)) {
//                    std::cerr << "diff improved from " << std::abs(val - target) << " to " << std::abs(newvalue - target) << '\n';
                    val = newvalue;
                } else {
                    result.fn[i-1] = 0;
                    result.fn[i] = 1; // restore
                    #ifdef DEBUG
                    result.eval();
                    assert(val == result.val);
                    #endif // DEBUG
                }
            } else if (val > target && result.fn[i-1] == 1) {
                result.fn[i-1] = 0;
                result.fn[i] = 1;
                double newvalue = result.eval();
//                if (!(newvalue <= val)) std::cerr << "Floating point sin-tan error 2\n";
                if (std::abs(newvalue - target) < std::abs(val - target)) {
//                    std::cerr << "diff improved from " << std::abs(val - target) << " to " << std::abs(newvalue - target) << '\n';
                    val = newvalue;
                } else {
                    result.fn[i-1] = 1;
                    result.fn[i] = 0; // restore
                    #ifdef DEBUG
                    result.eval();
                    assert(val == result.val);
                    #endif // DEBUG
                }
            }
        }
    }
    double newdiff = std::abs(val - target);
    if (newdiff < mindiff) {
        mindiff = std::abs(val - target);
        std::cerr << "ok\n";
    } else if (newdiff > mindiff) {
        std::cerr << "Program error : error value = " << (newdiff - mindiff) << " (should be <= 0 if correct) \n";
        std::cerr << "mindiff = " << mindiff << ", newdiff = " << newdiff << '\n';
    }
    result.eval(); // set result.result
    assert(val == result.val);

    return result;
}

expr nearest(const expr& in, double target) {
    stexpr tmp = nearest(in.val, target);
    expr result;
    for (int i = 0; i < tmp.length; ++i)
        result.expr.append(tmp.fn[i] ? "tan " : "sin ");

    result.expr = "(" + result.expr + in.expr + ")";
    result.val = tmp.val;
    return result;
}

int main() {
    double totalscore = 0;

    assert (std::numeric_limits<double>::is_iec559);
    std::cerr << std::setprecision(23);

//    double initial = 0.61575952241185627;
//    target = 0.6157595200093855;
//    stexpr a = nearest(initial, target);
//    std::cerr << a.val << ' ' << a.length << '\n';
//    return 0;

    while (std::cin >> digits[0]) {
        for (unsigned i = 1; i < digits.size(); ++i) std::cin >> digits[i];
        std::cin >> target;

/*        std::string e;
//        int sum = 0;
//        for (int i : digits) {
//            sum += i;
//            e.append(to_string(i)).push_back('+');
//        }
//        e.pop_back(); // remove the last '+'
//        e = "cos cos (" + e + ")";
//        double val = std::cos(std::cos((double)sum));
//
//        stexpr result = nearest(val, target); // cos(cos(x)) is in approx 0.5 - 1,
//        // so we can expect that sin(x) and tan(x) behaves reasonably nice
//        std::string fns;
//        for (int i = 0; i < result.length; ++i) fns.append(result.fn[i] ? "tan" : "sin").push_back(' ');
//
//        std::cout << (fns + e) << '\n';
//        continue;*/

        std::array<expr, NSOL> sols;
        expr a, b, c, d; // temporary for solutions

        /* ----------------------------------------
           solution 1 : nearest cos cos sum(digits) */

        a.clear();
        for (int i : digits) {
            a.val += i; // no floating-point error here
            a.expr.append(to_string(i)).push_back('+');
        }
        a.expr.pop_back(); // remove the last '+'
        a.expr = "(" + a.expr + ")";
        a.wrap1();

        sols[0] = nearest(a, target);


        /* -----------------------------------------
              solution 2 : a * tan(b) + c (also important) */

        // find b first, then a, then finally c
        a.clear(); b.clear(); c.clear(); // e = a, b = e1, c = e2

        a.expr = to_string(digits[0]);
        a.val = digits[0];
        a.wrap1();

        b.expr = "(" + to_string(digits[1]) + "+" + to_string(digits[2]) + ")";
        b.val = digits[1] + digits[2];
        b.wrap1();

        c.expr = to_string(digits[3]);
        c.val = digits[3];
        c.wrap1();

        d.expr = to_string(digits[4]);
        d.val = digits[4];
        d.wrap1();

        b = nearest(b, std::atan(target));

        double targetA = target / std::tan(b.val);
        int cnt = 0;
        while (targetA < 1 && targetA > 0.9) {
            ++cnt;
            targetA = targetA * targetA;
        }
        a = nearest(a, targetA);
        while (cnt --> 0) {
            a.val = std::sqrt(a.val);
            a.expr = "sqrt " + a.expr;
        }
        a.expr = "(" + a.expr + ")"; // handle number of the form 0.9999999999

        /// partition of any number to easy-to-calculate sum of 2 numbers
        {{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}

        double targetC, targetD; // near 1, not in [0.9, 1), >= 0.1
        // that is, [0.1, 0.9), [1, inf)

        double target1 = target - (a.val * std::tan(b.val));

        double ac = std::abs(target1), sc = sgn(target1);
        if (ac < .1) targetC = 1 + ac, targetD = -1;
        else if (ac < 1) targetC = 1 + ac/2, targetD = ac/2 - 1;
        else if (ac < 1.8 || ac > 2) targetC = targetD = ac/2;
        else targetC = .8, targetD = ac - .8;

        targetC *= sc; targetD *= sc;

        c = nearest(c, std::abs(targetC)); if (targetC < 0) c.val = -c.val, c.expr = "(-" + c.expr + ")";
        d = nearest(d, std::abs(targetD)); if (targetD < 0) d.val = -d.val, d.expr = "(-" + d.expr + ")";

        sols[1].expr = a.expr + "*tan " + b.expr + "+" + c.expr + "+" + d.expr;
        sols[1].val = a.val * std::tan(b.val) + c.val + d.val;

        std::cerr
        << "\n---Method 2---"
        << "\na = " << a.val
        << "\ntarget a = " << targetA
        << "\nb = " << b.val
        << "\ntan b = " << std::tan(b.val)
        << "\nc = " << c.val
        << "\ntarget c = " << targetC
        << "\nd = " << d.val
        << "\ntarget d = " << targetD
        << "\n";

        /* -----------------------------------------
              solution 3 : (b + c) */

        target1 = target / 2;
        b.clear(); c.clear();

        for (int i = 0; i < N_DIGIT; ++i) {
            expr &ex = (i < 2 ? b : c);
            ex.val += digits[i];
            ex.expr.append(to_string(digits[i])).push_back('+');
        }
        b.expr.pop_back();
        b.expr = "(" + b.expr + ")";
        b.wrap1();

        c.expr.pop_back();
        c.expr = "(" + c.expr + ")";
        c.wrap1();

        b = nearest(b, target1);
        c = nearest(c, target - target1); // approx. target / 2

        sols[2].expr = "(" + b.expr + "+" + c.expr + ")";
        sols[2].val = b.val + c.val;

        /* -----------------------------------------
              solution 4 : a (*|/) (b - c)  (important) */

        a.clear(); b.clear(); c.clear(); // a = a, b = e1, c = e2

        a.expr = to_string(digits[0]);
        a.val = digits[0];
        a.wrap1();

        b.expr = "(" + to_string(digits[1]) + "+" + to_string(digits[2]) + ")";
        b.val = digits[1] + digits[2];
        b.wrap1();

        c.expr = "(" + to_string(digits[3]) + "+" + to_string(digits[4]) + ")";
        c.val = digits[3] + digits[4];
        c.wrap1();


        // (b-c) should be minimized
        bool multiply = target < a.val;
        double factor = multiply ? target / a.val : a.val / target;

        target1 = 1 + 2 * factor; // 1 + 2 * factor and 1 + factor

        std::cerr << "* Method 4 :\n";
        std::cerr << "b initial = " << b.val << ", target = " << target1 << ", ";
        b = nearest(b, target1);
        std::cerr << " get " << b.val << '\n';

        std::cerr << "c initial = " << c.val << ", target = " << b.val - factor << ", ";
        c = nearest(c, b.val - factor); // factor ~= e1.val - e2.val
        std::cerr << " get " << c.val << '\n';

        sols[3].expr = "(" + a.expr + (multiply ? "*(" : "/(") +
        ( b.expr + "-" + c.expr )
        + "))";
        factor = b.val - c.val;
        sols[3].val = multiply ? a.val * factor : a.val / factor;

        std::cerr << "a.val = " << a.val << '\n';

        /* ----------------------------------
                    Final result */

        int minindex = 0;
        assert(NSOL != 0);
        for (int i = 0; i < NSOL; ++i) {
            if (std::abs(target - sols[i].val) < std::abs(target - sols[minindex].val)) minindex = i;
            std::cerr << "Sol " << i << ", diff = " << std::abs(target - sols[i].val) << "\n";
        }
        std::cerr << "Choose " << minindex << "; target = " << target << '\n';
        totalscore += std::abs(target - sols[minindex].val);

        std::cout << sols[minindex].expr << '\n';
    }

    // #undef cerr // in case no-debug
    std::cerr << "total score = " << totalscore << '\n';
}

Input from standard input, output to standard output.

user202729

Posted 2017-08-20T15:07:13.577

Reputation: 14 620

Yes, I think <1MB. Note that if the program violate something you can decrease N_ITER (currently is 1000) – user202729 – 2017-08-25T15:40:48.640

@geokavel Now it is questionable if 1 / sin_100000000 (2) is allowed, or sin_1.374059274 (1). – user202729 – 2017-08-25T17:11:09.943

1 / sin_100000000 (2) is allowed if you have the digits 1 and 2 at your disposal. I have no idea how sin_1.374059274 would work. What does it mean to repeat sin a non-integer number of times? – geokavel – 2017-08-25T17:14:01.177

@geokavel But the former formula takes forever to evaluate, so it is not hard to calculate the score. The later can be defined https://en.wikipedia.org/wiki/Iterated_function#Fractional_iterates_and_flows.2C_and_negative_iterates | How is the program on official test cases?

– user202729 – 2017-08-26T03:26:38.850

I see what you mean by a partial iteration, but I think it's too hard for me to implement it. Your program runs in good time - only about 25 seconds. – geokavel – 2017-08-26T03:50:08.937

@geokavel [Rescore] What is the "single player score" as in "score 0.0032 on official test" in the other answer? – user202729 – 2017-08-31T08:13:41.430

@geokavel And remember that the trignometric functions use radian. – user202729 – 2017-08-31T13:36:26.203

It refers to his average score on the test cases. – geokavel – 2017-08-31T15:00:36.547

@geokavel Rescore Because that is an math-library issue, you just need to add the fdlibm 5.3 library (which can be found for example here) and re-evaluate. You can also test if the file used the library by compiling the evaluator with the library and it should give the exact result as the Java evaluator. Besides, note that Java only guaranteed to produce the exact results if you use StrictMath instead of Math.

– user202729 – 2017-09-02T02:37:31.617

why should i rescore if Java already gives exact? – geokavel – 2017-09-02T03:00:54.600

I changed all functions to StrictMath and still same scores. I also tried compiling c++ evaluator with fdlibm 5.3, however it still gets different scores from Java. Does clang++ -std=c++11 -stdlib=libc++ -I ~/fdlibm53 -lm ~/fdlibm53/libfdm.a -o TestEval TestEval.cpp seem like correct command? – geokavel – 2017-09-02T03:57:26.163

I don't know how to use Linux or Mac, but if compiled correctly the evaluator should produce exactly correct result as Java evaluator. – user202729 – 2017-09-02T03:59:45.273

Must be doing something wrong, because c++ evaluator produces same results regardless of including libfdm. – geokavel – 2017-09-02T04:10:26.583

2

Python 2, radians, score 0.0032 on official test

This is the second draft solution gives an average score of 0.0032 points. As it uses a composition of a lot of sin I used the following compact notation for the output formula:

  • sin_1 x=sin(x)
  • sin_2 x=sin(sin(x))
  • ...
  • sin_7 x=sin(sin(sin(sin(sin(sin(sin(x)))))))
  • ...
import math
import bisect
s1=[[float(t) for t in e.split()] for e in s0.split('\n')]
maxi=int(1e7)
A=[]
B=[]
C=[]
D=[]
a=1
for i in range(maxi):
	A.append(a)
	C.append(1/a)
	b=math.sin(a)
	c=a-b
	B.append(1/c)
	D.append(c)
	a=b
B.sort() 
C.sort() 
A.sort() 
D.sort() 
d15={0:'sqrt_100 tan_4 cos_2 sin 0',1:'sqrt_100 tan_4 cos_2 sin 1',2:'sqrt_100 tan_2 cos_2 sin 2',3:'sqrt_100 tan_4 cos_2 sin 3',4:'sqrt_100 tan_4 cos_2 sin 4',5:'sqrt_100 tan_4 cos_2 sin 5',6:'sqrt_100 tan_4 cos_2 sin 6',7:'sqrt_100 tan_2 cos_2 sin 7',8:'sqrt_100 tan_2 cos_2 sin 8',9:'sqrt_100 tan_4 cos_2 sin 9'}
def d16(d):return '('+d15[d]+')'

def S0(l):
	cpt=0
	d=l[:-1]
	r=l[-1]
	a1,a2,a3,a4,a5=[int(t) for t in d]
	i1=bisect.bisect(B, r)-1
	w1=abs(r-B[i1])
	i2=bisect.bisect(C, w1)-1
	w2=abs(w1-C[i2]) 
	s='('+d16(a1)+'/(sin_'+str(i1)+' '+d16(a2)+'-'+'sin_'+str(i1+1)+' '+d16(a3)+')'+'+'+d16(a4)+'/sin_'+str(i2)+' '+d16(a5)+')'
	return (w2,s)

def S1(l):
	cpt=0
	d=l[:-1]
	r=l[-1]
	a1,a2,a3,a4,a5=[int(t) for t in d]
	i1=bisect.bisect(C, r)-1
	w1=abs(r-C[i1])
	i2=bisect.bisect(A, w1)-1
	w2=abs(w1-A[i2]) 
	s='('+d16(a1)+'/sin_'+str(i1)+' '+d16(a2)+'+sin_'+str(maxi-i2-1)+' ('+d16(a3)+'*'+d16(a4)+'*'+d16(a5)+')'
	return (w2,s)

def S2(l):
	cpt=0
	d=l[:-1]
	r=l[-1]
	a1,a2,a3,a4,a5=[int(t) for t in d]
	i1=bisect.bisect(A, r)-1
	w1=abs(r-A[i1])
	i2=bisect.bisect(D, w1)-1
	w2=abs(w1-D[i2]) 
	s='('+'(sin_'+str(maxi-i2-1)+' '+d16(a1)+'-'+'sin_'+str(maxi-i2)+' '+d16(a2)+')'+'+sin_'+str(maxi-i1-1)+' ('+d16(a3)+'*'+d16(a4)+'*'+d16(a5)+'))'
	return (w2,s)

def S3(l):
	cpt=0
	d=l[:-1]
	r=l[-1]
	a1,a2,a3,a4,a5=[int(t) for t in d]
	i1=bisect.bisect(A, r)-1
	w2=abs(r-A[i1])
	s='('+'sin_'+str(maxi-i1-1)+' ('+d16(a1)+'*'+d16(a2)+'*'+d16(a3)+'*'+d16(a4)+'*'+d16(a5)+'))'
	return (w2,s)

def S4(l):
	cpt=0
	d=l[:-1]
	r=l[-1]
	a1,a2,a3,a4,a5=[int(t) for t in d]
	i1=bisect.bisect(B, r)-1
	w2=abs(r-B[i1])
	s='('+d16(a1)+'/(sin_'+str(i1)+' '+d16(a2)+'-'+'sin_'+str(i1+1)+' '+d16(a3)+'*'+d16(a4)+'*'+d16(a5)+')'+')'
	return (w2,s)

def S5(l):
	cpt=0
	d=l[:-1]
	r=l[-1]
	a1,a2,a3,a4,a5=[int(t) for t in d]
	i1=bisect.bisect(C, r)-1
	w2=abs(r-C[i1])
	s='('+d16(a1)+'/sin_'+str(i1)+' '+d16(a2)+'*'+d16(a3)+'*'+d16(a4)+'*'+d16(a5)+')'
	return (w2,s)

def S6(l):
	cpt=0
	d=l[:-1]
	r=l[-1]
	a1,a2,a3,a4,a5=[int(t) for t in d]
	i1=bisect.bisect(D, r)-1
	w2=abs(r-D[i1])
	s='(sin_'+str(maxi-i1-1)+' '+d16(a1)+'-'+'sin_'+str(maxi-i1)+' '+d16(a2)+'*'+d16(a3)+'*'+d16(a4)+'*'+d16(a5)+')'
	return (w2,s)

def all4(s1):
	s=0
	for l in s1:
		f=min(S0(l),S1(l),S2(l),S3(l),S4(l),S5(l),S6(l))
		print f[1]
		s+=f[0]
	s/=len(s1)
	print 'average unofficial score:',s
all4(s1)

Try it online!

mdahmoune

Posted 2017-08-20T15:07:13.577

Reputation: 2 605

1Your program gets an moy of 49.70 on the official tests. For some reason it does really bad on a test case in section 3 with the following digits: 6 7 8 0 1. – geokavel – 2017-08-25T16:45:26.367

Your program outputs +(tan_4 cos_2 sin 6)/(sin_0((-(tan_4 cos_2 sin 7)-(tan_4 cos_2 sin 8)+(tan_4 cos_2 sin 0)+(tan_4 cos_2 sin 1)))) for that test case, which equals 0.145. – geokavel – 2017-08-25T16:58:33.653

Sorry, I wrote your official test score wrong the first time. You actually do a little worse than average on the official tests. – geokavel – 2017-08-29T19:39:29.130