mirror of
https://gitlab.com/square-game-liberation-front/F.E.I.S.git
synced 2025-02-28 15:30:32 +01:00
Fix some bugs with the fractions
This commit is contained in:
parent
7e93ea6845
commit
ec3779e1b4
@ -620,6 +620,7 @@ void EditorState::display_linear_view() {
|
|||||||
*chart_state,
|
*chart_state,
|
||||||
applicable_timing,
|
applicable_timing,
|
||||||
current_exact_beats(),
|
current_exact_beats(),
|
||||||
|
beats_at(editable_range.end),
|
||||||
get_snap_step(),
|
get_snap_step(),
|
||||||
ImGui::GetContentRegionMax()
|
ImGui::GetContentRegionMax()
|
||||||
);
|
);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <gmpxx.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
Fraction::Fraction(const Decimal& d) {
|
Fraction::Fraction(const Decimal& d) {
|
||||||
@ -90,7 +91,11 @@ Fraction operator%(Fraction lhs, const Fraction& rhs) {
|
|||||||
const auto db = rhs.value.get_den();
|
const auto db = rhs.value.get_den();
|
||||||
const auto na = lhs.value.get_num();
|
const auto na = lhs.value.get_num();
|
||||||
const auto nb = rhs.value.get_num();
|
const auto nb = rhs.value.get_num();
|
||||||
return Fraction{(na * db) % (nb * da), da * db};
|
const mpz_class dividend = na * db;
|
||||||
|
const mpz_class divisor = nb * da;
|
||||||
|
mpz_class remainder;
|
||||||
|
mpz_mod(remainder.get_mpz_t(), dividend.get_mpz_t(), divisor.get_mpz_t());
|
||||||
|
return Fraction{remainder, da * db};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::strong_ordering operator<=>(const Fraction& lhs, const Fraction& rhs) {
|
std::strong_ordering operator<=>(const Fraction& lhs, const Fraction& rhs) {
|
||||||
@ -160,11 +165,30 @@ std::uint64_t convert_to_u64(const mpz_class& z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Fraction floor_fraction(const Fraction& f) {
|
Fraction floor_fraction(const Fraction& f) {
|
||||||
return f - (f % Fraction{1});
|
mpz_class result;
|
||||||
|
mpz_fdiv_q(result.get_mpz_t(), f.numerator().get_mpz_t(), f.denominator().get_mpz_t());
|
||||||
|
return Fraction{result};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Thanks python again !
|
||||||
|
// https://github.com/python/cpython/blob/f163ad22d3321cb9bb4e6cbaac5a723444641565/Lib/fractions.py#L612
|
||||||
Fraction round_fraction(const Fraction& f) {
|
Fraction round_fraction(const Fraction& f) {
|
||||||
return floor_fraction(f + Fraction{1, 2});
|
mpz_class floor, remainder;
|
||||||
|
mpz_fdiv_qr(
|
||||||
|
floor.get_mpz_t(),
|
||||||
|
remainder.get_mpz_t(),
|
||||||
|
f.numerator().get_mpz_t(),
|
||||||
|
f.denominator().get_mpz_t()
|
||||||
|
);
|
||||||
|
if (remainder * 2 < f.denominator()) {
|
||||||
|
return Fraction{floor};
|
||||||
|
} else if (remainder * 2 > f.denominator()) {
|
||||||
|
return Fraction{floor + 1};
|
||||||
|
} else if (floor % 2 == 0) { // Deal with the half case
|
||||||
|
return Fraction{floor};
|
||||||
|
} else {
|
||||||
|
return floor + 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Fraction convert_to_fraction(const Decimal& d) {
|
Fraction convert_to_fraction(const Decimal& d) {
|
||||||
|
@ -20,7 +20,7 @@ TEST_CASE("Fractions") {
|
|||||||
SUBCASE("std::int64_t, returing the integral part") {
|
SUBCASE("std::int64_t, returing the integral part") {
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{1,2}) == INT64_C(0));
|
CHECK(static_cast<std::int64_t>(Fraction{1,2}) == INT64_C(0));
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{2,3}) == INT64_C(0));
|
CHECK(static_cast<std::int64_t>(Fraction{2,3}) == INT64_C(0));
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{-5,2}) == INT64_C(-2));
|
CHECK(static_cast<std::int64_t>(Fraction{-5,2}) == INT64_C(-3));
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{"-9223372036854775808/1"}) == INT64_MIN);
|
CHECK(static_cast<std::int64_t>(Fraction{"-9223372036854775808/1"}) == INT64_MIN);
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{"9223372036854775807/1"}) == INT64_MAX);
|
CHECK(static_cast<std::int64_t>(Fraction{"9223372036854775807/1"}) == INT64_MAX);
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{"-9000000000000000000/1"}) == INT64_C(-9000000000000000000));
|
CHECK(static_cast<std::int64_t>(Fraction{"-9000000000000000000/1"}) == INT64_C(-9000000000000000000));
|
||||||
@ -71,6 +71,23 @@ TEST_CASE("Fractions") {
|
|||||||
CHECK(Fraction{1,2} / Fraction{1,7} == Fraction{7,2});
|
CHECK(Fraction{1,2} / Fraction{1,7} == Fraction{7,2});
|
||||||
CHECK(Fraction{-1,2} / Fraction{1,2} == Fraction{-1,1});
|
CHECK(Fraction{-1,2} / Fraction{1,2} == Fraction{-1,1});
|
||||||
}
|
}
|
||||||
|
SUBCASE("are modulo'ed correctly") {
|
||||||
|
CHECK(Fraction{3,2} % Fraction{1} == Fraction{1,2});
|
||||||
|
CHECK(Fraction{23,14} % Fraction{2,5} == Fraction{3,70});
|
||||||
|
CHECK(Fraction{-7,4} % Fraction{1} == Fraction{1,4});
|
||||||
|
}
|
||||||
|
SUBCASE("are floor'ed correctly") {
|
||||||
|
CHECK(floor_fraction(Fraction{1,2}) == Fraction{0});
|
||||||
|
CHECK(floor_fraction(Fraction{23,14}) == Fraction{1});
|
||||||
|
CHECK(floor_fraction(Fraction{-7,4}) == Fraction{-2});
|
||||||
|
}
|
||||||
|
SUBCASE("are rounded correctly") {
|
||||||
|
CHECK(round_fraction(Fraction{10,20}) == Fraction{0});
|
||||||
|
CHECK(round_fraction(Fraction{11,20}) == Fraction{1});
|
||||||
|
CHECK(round_fraction(Fraction{-10,20}) == Fraction{0});
|
||||||
|
CHECK(round_fraction(Fraction{-11,20}) == Fraction{-1});
|
||||||
|
}
|
||||||
|
|
||||||
SUBCASE("support binary operand with") {
|
SUBCASE("support binary operand with") {
|
||||||
SUBCASE("integer literals") {
|
SUBCASE("integer literals") {
|
||||||
CHECK(Fraction{1,2} + 1 == Fraction{3,2});
|
CHECK(Fraction{1,2} + 1 == Fraction{3,2});
|
||||||
|
@ -58,6 +58,7 @@ void LinearView::update(
|
|||||||
const ChartState& chart_state,
|
const ChartState& chart_state,
|
||||||
const better::Timing& timing,
|
const better::Timing& timing,
|
||||||
const Fraction& current_beat,
|
const Fraction& current_beat,
|
||||||
|
const Fraction& last_editable_beat,
|
||||||
const Fraction& snap,
|
const Fraction& snap,
|
||||||
const ImVec2& size
|
const ImVec2& size
|
||||||
) {
|
) {
|
||||||
@ -75,9 +76,9 @@ void LinearView::update(
|
|||||||
// cursor_y pixels and we use this fact to compute the rest
|
// cursor_y pixels and we use this fact to compute the rest
|
||||||
const auto beats_before_cursor = beats_to_pixels_proportional.backwards_transform(cursor_y);
|
const auto beats_before_cursor = beats_to_pixels_proportional.backwards_transform(cursor_y);
|
||||||
const auto beats_after_cursor = beats_to_pixels_proportional.backwards_transform(static_cast<float>(y) - cursor_y);
|
const auto beats_after_cursor = beats_to_pixels_proportional.backwards_transform(static_cast<float>(y) - cursor_y);
|
||||||
const Fraction first_visible_beat = current_beat - beats_before_cursor;
|
const Fraction first_beat_in_frame = current_beat - beats_before_cursor;
|
||||||
const Fraction last_visible_beat = current_beat + beats_after_cursor;
|
const Fraction last_beat_in_frame = current_beat + beats_after_cursor;
|
||||||
AffineTransform<Fraction> beats_to_pixels_absolute{first_visible_beat, last_visible_beat, 0, y};
|
AffineTransform<Fraction> beats_to_pixels_absolute{first_beat_in_frame, last_beat_in_frame, 0, y};
|
||||||
|
|
||||||
float timeline_width = static_cast<float>(x) - 80.f;
|
float timeline_width = static_cast<float>(x) - 80.f;
|
||||||
float timeline_x = 50.f;
|
float timeline_x = 50.f;
|
||||||
@ -89,7 +90,7 @@ void LinearView::update(
|
|||||||
beat_number.setCharacterSize(15);
|
beat_number.setCharacterSize(15);
|
||||||
beat_number.setFillColor(sf::Color::White);
|
beat_number.setFillColor(sf::Color::White);
|
||||||
|
|
||||||
// Draw the beat lines and numbers
|
const Fraction first_visible_beat = std::max(Fraction{0}, first_beat_in_frame);
|
||||||
auto next_beat = [](const auto& first_beat) -> Fraction {
|
auto next_beat = [](const auto& first_beat) -> Fraction {
|
||||||
if (first_beat % 1 == 0) {
|
if (first_beat % 1 == 0) {
|
||||||
return first_beat;
|
return first_beat;
|
||||||
@ -98,9 +99,10 @@ void LinearView::update(
|
|||||||
}
|
}
|
||||||
}(first_visible_beat);
|
}(first_visible_beat);
|
||||||
|
|
||||||
|
// Draw the beat lines and numbers
|
||||||
for (
|
for (
|
||||||
Fraction next_beat_line_y = beats_to_pixels_absolute.transform(next_beat);
|
Fraction next_beat_line_y = beats_to_pixels_absolute.transform(next_beat);
|
||||||
next_beat_line_y < y;
|
next_beat_line_y < y and next_beat < last_editable_beat;
|
||||||
next_beat_line_y = beats_to_pixels_absolute.transform(next_beat += 1)
|
next_beat_line_y = beats_to_pixels_absolute.transform(next_beat += 1)
|
||||||
) {
|
) {
|
||||||
if (next_beat % 4 == 0) {
|
if (next_beat % 4 == 0) {
|
||||||
@ -182,9 +184,9 @@ void LinearView::update(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto first_visible_second = timing.time_at(first_visible_beat);
|
const auto first_visible_second = timing.time_at(first_beat_in_frame);
|
||||||
const auto first_visible_collision_zone = timing.beats_at(first_visible_second - sf::milliseconds(500));
|
const auto first_visible_collision_zone = timing.beats_at(first_visible_second - sf::milliseconds(500));
|
||||||
const auto last_visible_second = timing.time_at(last_visible_beat);
|
const auto last_visible_second = timing.time_at(last_beat_in_frame);
|
||||||
const auto last_visible_collision_zone = timing.beats_at(last_visible_second + sf::milliseconds(500));
|
const auto last_visible_collision_zone = timing.beats_at(last_visible_second + sf::milliseconds(500));
|
||||||
chart_state.chart.notes.in(
|
chart_state.chart.notes.in(
|
||||||
first_visible_collision_zone,
|
first_visible_collision_zone,
|
||||||
|
@ -18,6 +18,7 @@ public:
|
|||||||
const ChartState& chart_state,
|
const ChartState& chart_state,
|
||||||
const better::Timing& timing,
|
const better::Timing& timing,
|
||||||
const Fraction& current_beat,
|
const Fraction& current_beat,
|
||||||
|
const Fraction& last_editable_beat,
|
||||||
const Fraction& snap,
|
const Fraction& snap,
|
||||||
const ImVec2& size
|
const ImVec2& size
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user