void code_editor_widget::select_token(const std::string& row, int& begin_row, int& end_row, int& begin_col, int& end_col) { std::pair<int,int> key(begin_row, begin_col); if(bracket_match_.count(key)) { begin_row = bracket_match_.find(key)->second.front().first; begin_col = bracket_match_.find(key)->second.front().second; end_row = bracket_match_.find(key)->second.back().first; end_col = bracket_match_.find(key)->second.back().second+1; return; } text_editor_widget::select_token(row, begin_row, end_row, begin_col, end_col); std::string token(row.begin() + begin_col, row.begin() + end_col); boost::regex numeric_regex("-?\\d+(\\.\\d+)?", boost::regex::perl); std::cerr << "token: (" << token << ")\n"; if(boost::regex_match(token.c_str(), numeric_regex)) { const decimal current_value(decimal::from_string(token)); if(current_value <= 10000000 && current_value >= -10000000) { slider_.reset(new slider(200, boost::bind(&code_editor_widget::on_slider_move, this, _1))); slider_decimal_ = std::count(token.begin(), token.end(), '.') ? true : false; slider_magnitude_ = (abs(current_value.as_int())+1) * 5; const decimal slider_value = (current_value - decimal::from_int(-slider_magnitude_)) / decimal::from_int(slider_magnitude_*2); slider_->set_position(slider_value.as_float()); std::pair<int,int> pos = char_position_on_screen(begin_row, (begin_col+end_col)/2); row_slider_ = begin_row; begin_col_slider_ = begin_col; end_col_slider_ = end_col; int x = pos.second - slider_->width()/2; int y = pos.first + 20 - slider_->height(); if(x < 10) { x = 10; } if(x > width() - slider_->width()) { x = width() - slider_->width(); } if(y < 20) { y += 60; } if(y > height() - slider_->height()) { y = height() - slider_->height(); } slider_->set_loc(x, y); } } }
void decimal::suma(const decimal &sum) { // Por cada cifra del decimal, empezando por el final: // 1. Sumamos ambos numeros. // 2. Si la suma pasa de 10 acarreamos para la siguiente cifra, y restamos // 10 a la cifra actual. bool acarreo = false; for(unsigned int i = 0; i < cifs; ++i) { uint8_t op1 = this->get_cifra(i); uint8_t op2 = sum.get_cifra(i); uint8_t op3 = op1 + op2; if(acarreo) ++op3; if(op3 >= 10) { acarreo = true; op3 -= 10; } else { acarreo = false; } // Control para el overflow. if(acarreo && (i == cifs - 1)) this->set_cifra(10, i); else this->set_cifra(op3, i); } }
void decimal::resta(const decimal &res) { // Por cada cifra del decimal, empezando por el final: // 1. Comprobamos si operador 1 es mayor o igual operador 2. // 2. Si lo es, restamos. Si no, añadimos 10, indicando acarreo para el siguiente, y restamos. bool acarreo = false; for(unsigned int i = 0; i < cifs; ++i) { uint8_t op1 = this->get_cifra(i); uint8_t op2 = res.get_cifra(i); if(acarreo) ++op2; if(op1 < op2) { op1 += 10; acarreo = true; } else { acarreo = false; } int op3 = op1 - op2; this->set_cifra(op3, i); } }
bool operator==(const decimal &a, const decimal &b) { // 1. Comparamos signos. Si son diferentes devolvemos falso. // 2. Cambiamos el tamaño de b para que coincida con el de a. // 3. Comparamos cifra a cifra. if(a.is_negative() != b.is_negative()) return false; decimal t(b); t.resize(a.cifs, a.decs); for(int i = 0; i < static_cast<int>(a.long_buffer); ++i) if(a.buffer[i] != t.buffer[i]) return false; return true; }
inline decimal operator*(const decimal& a, const decimal& b) { const int64_t va = a.value() > 0 ? a.value() : -a.value(); const int64_t vb = b.value() > 0 ? b.value() : -b.value(); const int64_t ia = va/DECIMAL_PRECISION; const int64_t ib = vb/DECIMAL_PRECISION; const int64_t fa = va%DECIMAL_PRECISION; const int64_t fb = vb%DECIMAL_PRECISION; const decimal result = decimal(ia*ib*DECIMAL_PRECISION + fa*ib + fb*ia + (fa*fb)/DECIMAL_PRECISION); if(a.value() < 0 && b.value() > 0 || b.value() < 0 && a.value() > 0) { return -result; } else { return result; } }
decimal operator/(const decimal& a, const decimal& b) { int64_t va = a.value() > 0 ? a.value() : -a.value(); int64_t vb = b.value() > 0 ? b.value() : -b.value(); if(va == 0) { return a; } int64_t orders_of_magnitude_shift = 0; const int64_t target_value = DECIMAL(10000000000000); while(va < target_value) { va *= DECIMAL(10); ++orders_of_magnitude_shift; } const int64_t target_value_b = DECIMAL(1000000); while(vb > target_value_b) { vb /= DECIMAL(10); ++orders_of_magnitude_shift; } int64_t value = (va/vb); while(orders_of_magnitude_shift > 6) { value /= DECIMAL(10); --orders_of_magnitude_shift; } while(orders_of_magnitude_shift < 6) { value *= DECIMAL(10); ++orders_of_magnitude_shift; } const decimal result(decimal::from_raw_value(value)); if(a.value() < 0 && b.value() > 0 || b.value() < 0 && a.value() > 0) { return -result; } else { return result; } }
bool operator<=(const decimal &a, const decimal &b) { // 1. Comparamos signos. Si son distintos, el negativo es el menor. // 2. Cambiamos el tamaño de b para que coincida con el de a. // 3. Comparamos cifra a cifra, y devolvemos en consecuencia. if(a.is_negative() != b.is_negative()) return a.is_negative(); decimal t(b); t.resize(a.cifs, a.decs); bool a_menor = false, iguales = true; for(int i = a.cifs - 1; i >= 0; --i) { if(a.get_cifra(i) != t.get_cifra(i)) { iguales = false; if(a.get_cifra(i) < t.get_cifra(i)) { a_menor = true; } break; } } if(iguales) return true; // Invertimos el resultado si a y b son negativos. return a.is_negative() ? !a_menor : a_menor; }
decimal decimal::operator -=(const decimal& b) { if (b.isZero()) { return *this; } decimal& a = *this; const size_t w = a.length(); if (b.length() > w) { throw underflow_error("Negative values not allowed"); } bool borrow = false; for (size_t i = 0; i < w; i++) { digit d = a[i] - b[i] - (borrow ? 1 : 0); borrow = d < 0; a[i] = borrow ? 10 + d : d; } if (borrow) { throw underflow_error("Negative values not allowed"); } remove_lz(); return *this; }
decimal decimal::operator +=(const decimal& b) { if (isZero()) { *this = b; return *this; } else if (b.isZero()) { return *this; } decimal& a = *this; const size_t w = max(a.length(), b.length()); digits.resize(w + 1); bool carry = false; for (size_t i = 0; i < w; i++) { digit d = a[i] + b[i] + (carry ? 1 : 0); carry = d >= 10; a[i] = carry ? d - 10 : d; } if (carry) { a[w] = 1; } else { digits.resize(w); } return *this; }
decimal decimal::operator *(const decimal& value) const { const decimal& a = length() <= value.length() ? *this : value; const decimal& b = length() > value.length() ? *this : value; if (a.isZero()) { return decimal(0); } else if (a.isUnity()) { return b; } decimal c; const auto as = a.length(); const auto bs = b.length(); c.digits.resize(as + bs); for (size_t i = 0; i < as; i++) { const digit ad = a[i]; if (ad == 0) { continue; } decimal tmp; tmp.digits.resize(bs + i + 1); digit carry = 0; for (size_t j = 0; j < bs; j++) { digit d = b[j] * ad + carry; carry = d / 10; tmp[j + i] = d - (carry * 10); } if (carry) { tmp[bs + i] = carry; } else { tmp.digits.resize(bs + i); } c += tmp; } c.remove_lz(); return c; }
char decimal::relation_to(const decimal& b) const { const decimal& a = *this; const auto as = a.length(); const auto bs = b.length(); if (as > bs) { return +1; } else if (bs > as) { return -1; } for (auto i = as; i > 0; i--) { digit d = a[i - 1] - b[i - 1]; if (d > 0) { return +1; } else if (d < 0) { return -1; } } return 0; }
explicit variant(decimal d) : type_(VARIANT_TYPE_DECIMAL), decimal_value_(d.value()) {}
decimal decimal::parallel_multiply(const decimal& l, const decimal& r) { const decimal& a = l.length() <= r.length() ? l : r; const decimal& b = l.length() > r.length() ? l : r; if (a.isZero()) { return decimal(0); } else if (a.isUnity()) { return b; } const auto as = a.length(); const auto bs = b.length(); const size_t cores = std::thread::hardware_concurrency(); const size_t workers = min<size_t>(cores, (as / 1000)); if (workers == 0) { return l * r; } decimal result; result.digits.resize(as + bs); mutex mx; function<int(size_t, size_t)> partial_product = [&a, &b, as, bs, &mx, &result] (size_t begin, size_t end) { decimal c; c.digits.resize(as + bs); decimal tmp; tmp.digits.reserve(bs + end + 1); for (size_t i = begin; i < end; i++) { const digit ad = a[i]; if (ad == 0) { continue; } fill(tmp.digits.begin(), tmp.digits.end(), 0); tmp.digits.resize(bs + i + 1); digit carry = 0; for (size_t j = 0; j < bs; j++) { digit d = b[j] * ad + carry; carry = d / 10; tmp[j + i] = d - (carry * 10); } if (carry) { tmp[bs + i] = carry; } else { tmp.digits.resize(bs + i); } c += tmp; } lock_guard<mutex> lock(mx); result += c; return 0; }; vector<future<int>> futures; futures.reserve(workers); for (size_t worker = 0; worker < workers; worker++) { const auto begin = (as * worker) / workers; const auto end = (as * (worker + 1)) / workers; futures.emplace_back(async(std::launch::async, partial_product, begin, end)); } for (size_t worker = 0; worker < workers; worker++) { auto& future = futures[worker]; future.get(); } result.remove_lz(); return result; }
void code_editor_widget::select_token(const std::string& row, int& begin_row, int& end_row, int& begin_col, int& end_col) { std::pair<int,int> key(begin_row, begin_col); if(bracket_match_.count(key)) { begin_row = bracket_match_.find(key)->second.front().first; begin_col = bracket_match_.find(key)->second.front().second; end_row = bracket_match_.find(key)->second.back().first; end_col = bracket_match_.find(key)->second.back().second+1; return; } text_editor_widget::select_token(row, begin_row, end_row, begin_col, end_col); std::string token(row.begin() + begin_col, row.begin() + end_col); boost::regex numeric_regex("-?\\d+(\\.\\d+)?", boost::regex::perl); std::cerr << "token: (" << token << ")\n"; if(boost::regex_match(token.c_str(), numeric_regex)) { const decimal current_value(decimal::from_string(token)); if(current_value <= 10000000 && current_value >= -10000000) { slider_.reset(new slider(200, boost::bind(&code_editor_widget::on_slider_move, this, _1))); slider_decimal_ = std::count(token.begin(), token.end(), '.') ? true : false; slider_magnitude_ = (abs(current_value.as_int())+1) * 5; const decimal slider_value = (current_value - decimal::from_int(-slider_magnitude_)) / decimal::from_int(slider_magnitude_*2); slider_->set_position(slider_value.as_float()); slider_range_.clear(); slider_labels_.clear(); if(current_value > 0) { slider_range_.push_back(slider_range(0.0, 0.1, -current_value*5, -current_value)); slider_range_.push_back(slider_range(0.1, 0.2, -current_value, decimal(0))); slider_range_.push_back(slider_range(0.2, 0.3, decimal(0), current_value)); slider_range_.push_back(slider_range(0.3, 0.5, decimal(0), current_value)); slider_range_.push_back(slider_range(0.5, 0.7, current_value, 2*current_value)); slider_range_.push_back(slider_range(0.7, 0.9, 2*current_value, 5*current_value)); slider_range_.push_back(slider_range(0.9, 1.0, 5*current_value, 10*current_value)); slider_range_.push_back(slider_range(1.0, 2.0, 10*current_value, 20*current_value)); slider_->set_position(0.5); } else { slider_range_.push_back(slider_range(0.0, 0.5, current_value*2, decimal(0))); slider_range_.push_back(slider_range(0.5, 1.0, decimal(0), -current_value*2)); slider_range_.push_back(slider_range(1.0, 2.0, -current_value*2, -current_value*4)); slider_->set_position(0.25); } std::pair<int,int> pos = char_position_on_screen(begin_row, (begin_col+end_col)/2); row_slider_ = begin_row; begin_col_slider_ = begin_col; end_col_slider_ = end_col; int x = pos.second - slider_->width()/2; int y = pos.first + 20 - slider_->height(); if(x < 10) { x = 10; } if(x > width() - slider_->width()) { x = width() - slider_->width(); } if(y < 20) { y += 60; } if(y > height() - slider_->height()) { y = height() - slider_->height(); } slider_->set_loc(x, y); foreach(slider_range& r, slider_range_) { slider_labels_.push_back(widget_ptr(new gui::label(formatter() << r.target_begin, 10))); slider_labels_.back()->set_loc(x + slider_->width()*r.begin - slider_labels_.back()->width()/2, y); } }
inline bool operator<=(const decimal& a, const decimal& b) { return a.value() <= b.value(); }
inline decimal operator-(const decimal& a, const decimal& b) { return decimal(a.value() - b.value()); }