Created
May 19, 2018 20:29
-
-
Save AnthonyMikh/ba14d7fd191e7d2988ded337b093c449 to your computer and use it in GitHub Desktop.
Решение задачи №95 от UniLecs с обработкой ошибок
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Вспомогательный тип для удобства измерения площади | |
//(в единицах [длина ^ 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))); | |
} |
Вывод формулы для случая хорды:
Обозначим длину отрезка от центра большой окружности до точки пересечения диаметра, пересекающего центры всех окружностей, с хордой, через Δ. Тогда
Δ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
Playground: http://play.rust-lang.org/?gist=358c4d0cfdd2915c89652524da37413c&version=stable&mode=debug