Skip to content

Instantly share code, notes, and snippets.

@AnthonyMikh
Created May 19, 2018 20:29
Show Gist options
  • Save AnthonyMikh/ba14d7fd191e7d2988ded337b093c449 to your computer and use it in GitHub Desktop.
Save AnthonyMikh/ba14d7fd191e7d2988ded337b093c449 to your computer and use it in GitHub Desktop.
Решение задачи №95 от UniLecs с обработкой ошибок
//Вспомогательный тип для удобства измерения площади
//(в единицах [длина ^ 2] / π)
#[derive(Debug, PartialEq)]
struct PiFractions(f64);
//Сконвертировать PiFracions в нормальное число
impl ::std::convert::Into<f64> for PiFractions {
fn into(self) -> f64 {
self.0 * ::std::f64::consts::PI
}
}
//Возможные входные данные:
enum HoledCircle {
Radiuses(f64, f64), //радиусы внутренних окружностей;
Chord(f64), //длина разделительной хорды.
}
#[derive(Debug, PartialEq, Eq)]
enum InputKind {
FirstRadius,
SecondRadius,
Chord,
}
//Ошибки, связанные с некорректными входными данными
#[derive(Debug, PartialEq, Eq)]
enum InputError {
Malformed, //длина является NaN или бесконечностью
Negative, //длина меньше нуля
}
//Возможная ошибка при решении задачи -- это
//ошибка входных данных
//плюс указание, какое именно значение ошибочно
type HoledCircleError = (InputError, InputKind);
//Проверка корректности входных данных
fn check_input(x: &f64) -> Result<(), InputError> {
use InputError::*;
if x.is_infinite() || x.is_nan() {
return Err(Malformed);
}
if *x < 0.0 {
return Err(Negative);
}
Ok(())
}
//Считает плошадь большого круга за вычетом площадей маленьких, делённую на π.
//Возвращает ошибку при некорректных входных данных
fn holed_circle_area(input: &HoledCircle) -> Result<PiFractions, HoledCircleError> {
use HoledCircle::*;
use InputKind::{FirstRadius, SecondRadius};
match input {
//Если переданы два радиуса
Radiuses(r1, r2) => {
//Проверяем их корректность
check_input(r1).map_err(|e| (e, FirstRadius))?;
check_input(r2).map_err(|e| (e, SecondRadius))?;
//S / π = R^2 - r1^2 - r2^2
// = (r1 + r2)^2 - r1^2 - r2^2
// = r1^2 + 2*r1*r2 + r2^2 - r1^2 - r2^2
// = 2*r1*r2
Ok(PiFractions(2.0 * r1 * r2))
},
//Если передана длина хорды
Chord(t) => {
//Проверяем её корректность
check_input(t).map_err(|e| (e, InputKind::Chord))?;
//См. комментарии к гисту
Ok(PiFractions(t * t / 8.0))
},
}
}
//-------------------- Тесты -----------------------
#[test]
fn some_variants() {
use HoledCircle::*;
assert_eq!(holed_circle_area(&Radiuses(3.0, 4.0)), Ok(PiFractions(24.0)));
assert_eq!(holed_circle_area(&Chord(4.0)), Ok(PiFractions(2.0)));
const PI_2: f64 = ::std::f64::consts::PI * 2.0;
assert_eq!(holed_circle_area(&Chord(4.0)).map(Into::into), Ok(PI_2));
}
#[test]
fn check_malformed() {
use HoledCircle::*;
use InputError::*;
use InputKind::{FirstRadius, SecondRadius};
let bad_r = 0.0 / 0.0;
let bad_chord = 1.0 / 0.0;
assert_eq!(holed_circle_area(&Radiuses(bad_r, 1.0)), Err((Malformed, FirstRadius)));
assert_eq!(holed_circle_area(&Radiuses(2.0, bad_r)), Err((Malformed, SecondRadius)));
assert_eq!(holed_circle_area(&Chord(bad_chord)), Err((Malformed, InputKind::Chord)));
}
#[test]
fn check_negative() {
use HoledCircle::*;
use InputError::*;
use InputKind::{FirstRadius, SecondRadius};
let neg_r = -1.0;
let neg_chord = -1.0;
assert_eq!(holed_circle_area(&Radiuses(neg_r, 1.0)), Err((Negative, FirstRadius)));
assert_eq!(holed_circle_area(&Radiuses(2.0, neg_r)), Err((Negative, SecondRadius)));
assert_eq!(holed_circle_area(&Chord(neg_chord)), Err((Negative, InputKind::Chord)));
}
@AnthonyMikh
Copy link
Author

@AnthonyMikh
Copy link
Author

AnthonyMikh commented May 19, 2018

Вывод формулы для случая хорды:
Обозначим длину отрезка от центра большой окружности до точки пересечения диаметра, пересекающего центры всех окружностей, с хордой, через Δ. Тогда

Δ2 = R2 - t'2, где t' = t/2
r1 = (R + Δ)/2
r2 = (R - Δ)/2

S/π
= R2 - r12 - r22
= R2 - ¼(R + Δ)2 - ¼(R - Δ)2
= R2 - ¼R2 - ½RΔ - ¼Δ2 - ¼R2 + ½RΔ - ¼Δ2
= ½(R2 + Δ2)
= ½(R2 + (R2 - t'2))
= ½t'2
= ⅛t2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment