Я ищу тестовый вывод моей функции (которая возвращает массив) с ожидаемым выходным массивом.
Пример:
use Test;
sub myoutput($n) {
(1..$n)>>.sqrt
}
is myoutput(3), (1, 1.4142135623730951, 1.7320508075688772);
Выглядит нормально, но я хочу установить точность 1e-12
.
У меня получилось следующее:
sub element_wise_testing_with_precision(@functionoutput, @expectedoutput, $precision) {
die "Provide equal elements!" if +@functionoutput != +@expectedoutput;
loop (my $i = 0; $i < +@functionoutput; $i++) {
is-approx @functionoutput[$i], @expectedoutput[$i], $precision;
}
}
my @expected = (1, 1.4142135623730951, 1.7320508075688772);
element_wise_testing_with_precision(myoutput(3), @expected, 1e-12)
Работает (!), но не уверен, что это правильно. Существуют ли способы сделать это с помощью оператора Z или Гипероператора, поскольку они, похоже, выполняют поэлементные операции?
Это :$abs-tol
, абсолютная точность.
Ваши представления о Hyper и zip/операторе Z совершенно верны: с любым из них можно делать все, что хочешь. Недостающий кусочек головоломки — это каррирование , которое Раку делает с помощью &предполагая (или с помощью Что угодно каррирования, но это здесь неприменимо). Мы можем использовать &assuming
, чтобы указать точность в качестве третьего аргумента, например: &is-approx.assuming(*, *, $precision)
. Или, поскольку &is-approx
позволяет указать точность с помощью именованного аргумента, мы можем упростить это до &is-approx.assuming: :abs-tol($precision)
.
Как только мы это сделаем, мы можем применить наш новый элемент функции с помощью метаоператоров Hyper или Z. Обратите внимание: поскольку метаоператоры ожидают инфиксный оператор, нам нужно будет использовать инфиксную форму нашей функции, заключая нашу функцию в квадратные скобки.
Вот ваш код с этими минимальными изменениями:
sub element_wise_testing_with_precision(@functionoutput, @expectedoutput, $precision) {
die "Provide equal elements!" if +@functionoutput != +@expectedoutput;
my &close-enough = &is-approx.assuming(*,*, $precision);
@functionoutput «[&close-enough]» @expectedoutput
# or this also works:
# @functionoutput Z[&close-enough] @expectedoutput
}
Вот версия с некоторыми изменениями, чтобы сделать ее более идиоматичной:
sub element-wise-is-approx(@got, @expected, $abs-tol) {
PRE { +@got == +@expected }
my &close-enough = &is-approx.assuming: :$abs-tol;
@got «[&close-enough]» @expected
}
element-wise-is-approx(myoutput(3), @expected, 1e-12);
Действительно, мы могли бы сделать это даже в строке, как показано ниже. Здесь мы переключаемся на версию Hyper (» «
), не поддерживающую DWIM, чтобы обеспечить использование аргументов одинакового размера.
myoutput(3) »[&(&is-approx.assuming(*,*,1e-12))]« @expected
(Обратите внимание, что дополнительный &( )
в инфиксном операторе необходим для разъяснения наших намерений компилятору Raku.)
Как всегда отличное объяснение. Много нового для меня. Спасибо @codesections Несколько комментариев: во второй функции @got «[&is-approx]» @expected
может быть опечатка, думаю, &close-enough
должно быть посередине. В вашем третьем коде я получаю это предупреждение Potential difficulties: Useless use of »[&(&is-approx.assuming(*,*,1e-12))]« in sink context
. Есть идеи, как от этого избавиться?
@SumanKhanal, спасибо за указание на (теперь исправленную) опечатку и предупреждение о «контексте приемника». Я считаю, что последнее — ошибка Ракудо; Я сообщу о проблеме, если ее еще нет. Пока это не исправлено, вы можете отключить предупреждение, присвоив результат неиспользуемой переменной my $ = myoutput(3) »[&(&is-approx.assuming(*,*,1e-12))]« @expected
или запустив ее в subtest
. Или отключить все предупреждения с помощью блока quietly
(docs.raku.org/syntax/quietly%20%28statement%20prefix%29), но здесь это кажется излишним.
Ошибка уже была: github.com/rakudo/rakudo/issues/4424 Я добавил некоторые подробности и дал ссылку на этот вопрос SO.
Это кажется чрезвычайно продвинутым ответом, особенно для новых пользователей Raku. Есть ли шанс, что ОП сочтет $*TOLERANCE
из 1e-15
приемлемым? См. второй ответ на этот вопрос (при желании добавьте .grep
).
Мне неясно, хочет ли ФП абсолютной или относительной терпимости. Может ли @SumanKhanal внести ясность?
@jubilatious1 Это :$abs-tol, абсолютная точность.
Попробуйте встроенный в Raku оператор =~=
«толерантности» с вызовами Hyper/Z, которые вы себе представляете.
Оператор «допуска» =~=
считывает динамическую переменную $*TOLERANCE
, которая по умолчанию равна 1e-15
, см. ссылку внизу.
~$ seq 1 16 | \
awk '{print sqrt($0)}' | \
raku -e 'my @awk = lines;
my @raku = (1..16).map: *.sqrt; \
.say for [Z=~=] @awk,@raku;'
True
False
False
True
False
False
False
False
True
False
False
False
False
False
False
True
Выделение входных данных, первый awk:
~$ seq 1 16 | awk '{print sqrt($0)}'
1
1.41421
1.73205
2
2.23607
2.44949
2.64575
2.82843
3
3.16228
3.31662
3.4641
3.60555
3.74166
3.87298
4
И точность Раку по умолчанию:
~$ raku -e '.sqrt.put for (1..16);'
1
1.4142135623730951
1.7320508075688772
2
2.23606797749979
2.449489742783178
2.6457513110645907
2.8284271247461903
3
3.1622776601683795
3.3166247903554
3.4641016151377544
3.605551275463989
3.7416573867739413
3.872983346207417
4
Я понимаю, что ФП запросил допуск 1e-12
, но, может быть, более высокий допуск 1e-15
может оказаться приемлемым? Не видя желаемого результата ОП, я могу только догадываться, что однострочник [Z=~=]
может быть приемлемым, с дополнительным вызовом .grep
или без него.
[ Re: Допуск — я не вижу способа установить динамическую переменную $*TOLERANCE
так, чтобы инфиксный оператор =~=
считывал новое значение. Установка $*TOLERANCE = 1e-12
выдает ошибку. Невозможно изменить неизменяемый Num (1e-15)].
[Раку также имеет похожую функцию, is-approx
].
https://docs.raku.org/routine/%3D~%3D
https://docs.raku.org/routine/is-approx
https://unix.stackexchange.com/a/742940/227738
my $*TOLERANCE = ...
сделал бы новую лексическую динамическую переменную для =~=, чтобы ее можно было видеть, не затрагивая глобальную, живущую в ПРОЦЕССЕ, которая привязана к 1e-15, настолько неизменной, как вы сказали, что, я думаю, хорошо, чтобы не менять глобально толерантность повсюду. И что еще более важно, это проверяет относительную разницу, а не абсолютную, которую задавший вопрос достигает с помощью параметра abs-tol is-approx.
Абсолютная точность или относительная точность?