<commit_before>//
//  StandardFunctions.swift
//  DDMathParser
//
//  Created by <NAME> on 8/20/15.
//
//

import Foundation

extension Function {
    
    // MARK: - Angle mode helpers
    
    internal static func _dtor(_ d: Double, evaluator: Evaluator) -> Double {
        guard evaluator.angleMeasurementMode == .degrees else { return d }
        return d / 180 * Double.pi
    }
    
    internal static func _rtod(_ d: Double, evaluator: Evaluator) -> Double {
        guard evaluator.angleMeasurementMode == .degrees else { return d }
        return d / Double.pi * 180
    }
    
    public static let standardFunctions: Array<Function> = [
        add, subtract, multiply, divide,
        mod, negate, factorial, factorial2,
        pow, sqrt, cuberoot, nthroot,
        random, abs, percent,
        log, ln, log2, exp,
        and, or, not, xor, lshift, rshift,
        sum, product,
        count, min, max, average, median, stddev,
        ceil, floor,
        sin, cos, tan, asin, acos, atan, atan2,
        csc, sec, cotan, acsc, asec, acotan,
        sinh, cosh, tanh, asinh, acosh, atanh,
        csch, sech, cotanh, acsch, asech, acotanh,
        versin, vercosin, coversin, covercosin, haversin, havercosin, hacoversin, hacovercosin, exsec, excsc, crd,
        dtor, rtod,
        `true`, `false`,
        phi, pi, pi_2, pi_4, tau, sqrt2, e, log2e, log10e, ln2, ln10,
        l_and, l_or, l_not, l_eq, l_neq, l_lt, l_gt, l_ltoe, l_gtoe, l_if
    ]
    
    // MARK: - Basic functions
    
    public static let add = Function(name: "add", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        return arg1 + arg2
    })
    
    public static let subtract = Function(name: "subtract", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        return arg1 - arg2
    })
    
    public static let multiply = Function(names: ["multiply", "implicitmultiply"], evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        return arg1 * arg2
    })
    
    public static let divide = Function(name: "divide", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        guard arg2 != 0 else { throw MathParserError(kind: .divideByZero, range: state.expressionRange) }
        return arg1 / arg2
    })
    
    public static let mod = Function(names: ["mod", "modulo"], evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        return fmod(arg1, arg2)
    })
    
    public static let negate = Function(name: "negate", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        
        return -arg1
    })
    
    public static let factorial = Function(name: "factorial", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        return arg1.factorial()
    })
    
    public static let factorial2 = Function(name: "factorial2", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        guard arg1 >= 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        guard arg1 == Darwin.floor(arg1) else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        if arg1.truncatingRemainder(dividingBy: 2) == 0 {
            let k = arg1 / 2
            return Darwin.pow(2, k) * k.factorial()
        } else {
            let k = (arg1 + 1) / 2
            
            let numerator = (2*k).factorial()
            let denominator = Darwin.pow(2, k) * k.factorial()
            
            guard denominator != 0 else { throw MathParserError(kind: .divideByZero, range: state.expressionRange) }
            return numerator / denominator
        }
    })
    
    public static let pow = Function(name: "pow", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        return Darwin.pow(arg1, arg2)
    })
    
    public static let sqrt = Function(name: "sqrt", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let value = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        
        return Darwin.sqrt(value)
    })
    
    public static let cuberoot = Function(name: "cuberoot", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        
        return Darwin.pow(arg1, 1.0/3.0)
    })
    
    public static let nthroot = Function(name: "nthroot", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        guard arg2 != 0 else { throw MathParserError(kind: .divideByZero, range: state.expressionRange) }
        
        if arg1 < 0 && arg2.truncatingRemainder(dividingBy: 2) == 1 {
            // for negative numbers with an odd root, the result will be negative
            let root = Darwin.pow(-arg1, 1/arg2)
            return -root<commit_msg>Updated to fix -neg num for cube root<commit_after>//
//  StandardFunctions.swift
//  DDMathParser
//
//  Created by <NAME> on 8/20/15.
//
//

import Foundation

extension Function {
    
    // MARK: - Angle mode helpers
    
    internal static func _dtor(_ d: Double, evaluator: Evaluator) -> Double {
        guard evaluator.angleMeasurementMode == .degrees else { return d }
        return d / 180 * Double.pi
    }
    
    internal static func _rtod(_ d: Double, evaluator: Evaluator) -> Double {
        guard evaluator.angleMeasurementMode == .degrees else { return d }
        return d / Double.pi * 180
    }
    
    public static let standardFunctions: Array<Function> = [
        add, subtract, multiply, divide,
        mod, negate, factorial, factorial2,
        pow, sqrt, cuberoot, nthroot,
        random, abs, percent,
        log, ln, log2, exp,
        and, or, not, xor, lshift, rshift,
        sum, product,
        count, min, max, average, median, stddev,
        ceil, floor,
        sin, cos, tan, asin, acos, atan, atan2,
        csc, sec, cotan, acsc, asec, acotan,
        sinh, cosh, tanh, asinh, acosh, atanh,
        csch, sech, cotanh, acsch, asech, acotanh,
        versin, vercosin, coversin, covercosin, haversin, havercosin, hacoversin, hacovercosin, exsec, excsc, crd,
        dtor, rtod,
        `true`, `false`,
        phi, pi, pi_2, pi_4, tau, sqrt2, e, log2e, log10e, ln2, ln10,
        l_and, l_or, l_not, l_eq, l_neq, l_lt, l_gt, l_ltoe, l_gtoe, l_if
    ]
    
    // MARK: - Basic functions
    
    public static let add = Function(name: "add", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        return arg1 + arg2
    })
    
    public static let subtract = Function(name: "subtract", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        return arg1 - arg2
    })
    
    public static let multiply = Function(names: ["multiply", "implicitmultiply"], evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        return arg1 * arg2
    })
    
    public static let divide = Function(name: "divide", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        guard arg2 != 0 else { throw MathParserError(kind: .divideByZero, range: state.expressionRange) }
        return arg1 / arg2
    })
    
    public static let mod = Function(names: ["mod", "modulo"], evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        return fmod(arg1, arg2)
    })
    
    public static let negate = Function(name: "negate", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        
        return -arg1
    })
    
    public static let factorial = Function(name: "factorial", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        return arg1.factorial()
    })
    
    public static let factorial2 = Function(name: "factorial2", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        guard arg1 >= 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        guard arg1 == Darwin.floor(arg1) else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        if arg1.truncatingRemainder(dividingBy: 2) == 0 {
            let k = arg1 / 2
            return Darwin.pow(2, k) * k.factorial()
        } else {
            let k = (arg1 + 1) / 2
            
            let numerator = (2*k).factorial()
            let denominator = Darwin.pow(2, k) * k.factorial()
            
            guard denominator != 0 else { throw MathParserError(kind: .divideByZero, range: state.expressionRange) }
            return numerator / denominator
        }
    })
    
    public static let pow = Function(name: "pow", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        return Darwin.pow(arg1, arg2)
    })
    
    public static let sqrt = Function(name: "sqrt", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let value = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        
        return Darwin.sqrt(value)
    })
    
    public static let cuberoot = Function(name: "cuberoot", evaluator: { state throws -> Double in
        guard state.arguments.count == 1 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        
        if arg1 < 0 {
            let root = Darwin.pow(-arg1, 1.0/3.0)
            return -root
        } else {
            return Darwin.pow(arg1, 1.0/3.0)
        }
    })
    
    public static let nthroot = Function(name: "nthroot", evaluator: { state throws -> Double in
        guard state.arguments.count == 2 else { throw MathParserError(kind: .invalidArguments, range: state.expressionRange) }
        
        let arg1 = try state.evaluator.evaluate(state.arguments[0], substitutions: state.substitutions)
        let arg2 = try state.evaluator.evaluate(state.arguments[1], substitutions: state.substitutions)
        
        guard arg2 != 0 else { throw MathParserError(kind: .divideByZero, range: state.expressionRange) }
        
        if arg1 < 0 && arg2.truncatingRemainder(dividingBy: 2) == 1 {
            // for negative numbers with an odd root, the result will be negative
            let root = Darwin.pow(-arg1, 1/arg2)
            return -root
{'fraction_non_alphanumeric': 0.10449424291197226, 'fraction_numerical': 0.015414138912962734, 'mean_word_length': 2.7129395541254886, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1457544', 'n_tokens_mistral': 4863, 'n_tokens_neox': 4631, 'n_words': 1294}