<commit_before>/*
 * rational.cpp
 */
#include "rational.h"

namespace c8 {
    rational::rational(const std::string &v) {
        /*
         * Do we have a '/' character separating a numerator and denominator?
         */
        std::size_t pos = v.find(std::string("/"));
        if (pos == std::string::npos) {
            num_ = integer(v);
        } else {
            num_ = integer(v.substr(0, pos));
            denom_ = natural(v.substr(pos + 1));
        }

        normalize();
    }

    /*
     * Add another rational to this one.
     */
    auto rational::add(const rational &v) const -> rational {
        rational res;

        res.num_ = (num_ * integer(v.denom_)) + (integer(denom_) * v.num_);
        res.denom_ = denom_ * v.denom_;

        res.normalize();

        return res;
    }

    /*
     * Subtract another rational from this one.
     *
     * Note that there is a subtle difference between the rational subtract operation
     * and the natural number version: We don't have to worry about throwing
     * exceptions for negative results.
     */
    auto rational::subtract(const rational &v) const -> rational {
        rational res;

        res.num_ = (num_ * integer(v.denom_)) - (integer(denom_) * v.num_);
        res.denom_ = denom_ * v.denom_;

        res.normalize();

        return res;
    }

    /*
     * Multiply another rational with this one.
     */
    auto rational::multiply(const rational &v) const -> rational {
        rational res;

        res.num_ = num_ * v.num_;
        res.denom_ = denom_ * v.denom_;

        res.normalize();

        return res;
    }

    /*
     * Divide this rational by another one.
     */
    auto rational::divide(const rational &v) const -> rational {
        rational res;

        res.num_ = num_ * integer(v.denom_);
        integer d = integer(denom_) * v.num_;
        if (isnegative(d)) {
            res.num_ = -res.num_;
        }
        res.denom_ = abs(d);

        res.normalize();

        return res;
    }

    /*
     * Compare a rational with this one.
     */
    auto rational::compare(const rational &v) const -> rational_comparison {
        integer lhs = num_ * integer(v.denom_);
        integer rhs = v.num_ * integer(denom_);

        auto ures = lhs.compare(rhs);
        switch (ures) {
        case integer_comparison::lt:
            return rational_comparison::lt;

        case integer_comparison::eq:
            return rational_comparison::eq;

        case integer_comparison::gt:
            return rational_comparison::gt;
        }
    }

    /*
     * Normalize the data.
     */<commit_msg>Add divide-by-zero exception for rationals<commit_after>/*
 * rational.cpp
 */
#include "rational.h"

namespace c8 {
    rational::rational(const std::string &v) {
        /*
         * Do we have a '/' character separating a numerator and denominator?
         */
        std::size_t pos = v.find(std::string("/"));
        if (pos == std::string::npos) {
            num_ = integer(v);
        } else {
            num_ = integer(v.substr(0, pos));
            denom_ = natural(v.substr(pos + 1));
        }

        normalize();
    }

    /*
     * Add another rational to this one.
     */
    auto rational::add(const rational &v) const -> rational {
        rational res;

        res.num_ = (num_ * integer(v.denom_)) + (integer(denom_) * v.num_);
        res.denom_ = denom_ * v.denom_;

        res.normalize();

        return res;
    }

    /*
     * Subtract another rational from this one.
     *
     * Note that there is a subtle difference between the rational subtract operation
     * and the natural number version: We don't have to worry about throwing
     * exceptions for negative results.
     */
    auto rational::subtract(const rational &v) const -> rational {
        rational res;

        res.num_ = (num_ * integer(v.denom_)) - (integer(denom_) * v.num_);
        res.denom_ = denom_ * v.denom_;

        res.normalize();

        return res;
    }

    /*
     * Multiply another rational with this one.
     */
    auto rational::multiply(const rational &v) const -> rational {
        rational res;

        res.num_ = num_ * v.num_;
        res.denom_ = denom_ * v.denom_;

        res.normalize();

        return res;
    }

    /*
     * Divide this rational by another one.
     */
    auto rational::divide(const rational &v) const -> rational {
        rational res;

        /*
         * Are we attempting to divide by zero?  If we are then throw an exception.
         */
        if (iszero(abs(v.num_))) {
            throw std::logic_error("divide_by_zero");
        }

        res.num_ = num_ * integer(v.denom_);
        integer d = integer(denom_) * v.num_;
        if (isnegative(d)) {
            res.num_ = -res.num_;
        }

        res.denom_ = abs(d);

        res.normalize();

        return res;
    }

    /*
     * Compare a rational with this one.
     */
    auto rational::compare(const rational &v) const -> rational_comparison {
        integer lhs = num_ * integer(v.denom_);
        integer rhs = v.num_ * integer(denom_);

        auto ures = lhs.compare(rhs);
        switch (ures) {
        case integer_comparison::lt:
            return rational_comparison::lt;

        case integer_comparison::eq:
            return rational_comparison::eq;

        case integer_comparison::gt:
            return rational_comparison::gt;
        }
    }

    /*
     * Normalize the data.
     */
{'fraction_non_alphanumeric': 0.11868732907930721, 'fraction_numerical': 0.0010938924339106654, 'mean_word_length': 1.8090117767537122, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, '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': '6491735', 'n_tokens_mistral': 1676, 'n_tokens_neox': 1605, 'n_words': 434}