Буквально самый простой способ исправить NullReferenceExeption имеет два пути. Если у вас есть GameObject, например, с прикрепленным скриптом и переменной с именем rb (rigidbody), эта переменная начнет пустую, когда вы начнете игру. Вот почему вы получаете NullReferenceExeption, потому что на компьютере нет данных, хранящихся в этой переменной.
В качестве примера я буду использовать переменную RigidBody. Мы можем добавить данные действительно легко на самом деле несколькими способами:
rb = GetComponent<Rigidbody>();
. Эта строка кода работает лучше всего под ваши функции Start()
или Awake()
. rb = AddComponent<RigidBody>();
Дальнейшие заметки: если вы хотите, чтобы единство добавлялось компонент для вашего объекта, и вы, возможно, забыли добавить его, вы можете ввести [RequireComponent(typeof(RigidBody))]
над объявлением класса (пробел ниже всех ваших приложений). Наслаждайтесь и получайте удовольствие от игр!
См. Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой .
Ничто из этого не является специфичным для Perl: существует бесчисленное множество действительных чисел и, очевидно, все они не могут быть представлены с использованием только конечного числа бит.
Конкретные «Решение» для использования зависит от конкретной проблемы. Вы пытаетесь отслеживать денежные суммы? Если это так, используйте произвольные номера точности (используйте больше памяти и больше ЦП, получите более точные результаты), предоставленные bignum . Вы делаете числовой анализ? Затем определите точность, которую вы хотите использовать, и используйте sprintf
(как показано ниже) и eq
для сравнения.
Вы всегда можете использовать:
use strict; use warnings;
check_summation(1, $_) for [1, 2, 3], [1.1, 2.2, 3.3];
sub check_summation {
my $precision = shift;
my ($x, $y, $expected) = @{ $_[0] };
my $result = $x + $y;
for my $n ( $x, $y, $expected, $result) {
$n = sprintf('%.*f', $precision, $n);
}
if ( $expected eq $result ) {
printf "%s + %s = %s\n", $x, $y, $expected;
}
else {
printf "%s + %s != %s\n", $x, $y, $expected;
}
return;
}
Выход:
1.0 + 2.0 = 3.0 1.1 + 2.2 = 3.3
Чтобы увидеть точные значения для ваших скаляров с плавающей запятой, дайте большую точность sprintf
:
print sprintf("%.60f", 1.1), $/;
print sprintf("%.60f", 2.2), $/;
print sprintf("%.60f", 3.3), $/;
Получаю:
1.100000000000000088817841970012523233890533447265625000000000
2.200000000000000177635683940025046467781066894531250000000000
3.299999999999999822364316059974953532218933105468750000000000
К сожалению, C99% a преобразование, похоже, не работает. perlvar
упоминает устаревшую переменную $#
, которая меняет формат по умолчанию для печати числа, но он ломается, если я даю ему% f, а% g отказывается печатать «несущественные» цифры.
«Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой»
В принципе, Perl имеет дело с числами с плавающей запятой, в то время как вы, вероятно, ожидаете, что он будет использовать фиксированные -точка. Самый простой способ справиться с этой ситуацией - изменить свой код, чтобы вы использовали целые числа везде, кроме, возможно, в финальной программе отображения. Например, если вы имеете дело с валютой доллара США, храните все суммы в долларах в гроши. 123 доллара и 45 центов становятся «12345». Таким образом, не существует неопределенности с плавающей запятой во время операций добавления и вычитания.
Если это не вариант, рассмотрите комментарий Мэтта Кейна . Найти хорошее значение epsilon и использовать его всякий раз, когда вам нужно сравнивать значения.
Я бы рискнул предположить, что большинство задач на самом деле не нужны с плавающей запятой, и я 'd настоятельно рекомендуем тщательно подумать, является ли он правильным инструментом для вашей задачи.
Из Руководство по плавающей запятой :
Почему мои цифры, например, 0,1 + 0,2, не совпадают с хорошим раундом 0,3, и вместо этого я получаю странный результат, например, 0,30000000000000004?
. Поскольку внутренне компьютеры используют формат (двоичный с плавающей запятой), который не может точно представлять число, например 0,1, 0,2 или 0,3.
Когда код скомпилирован или интерпретирован, ваш «0,1» уже округлен до ближайшего номера в этом формате, что приводит к небольшой ошибке округления даже до того, как произойдет расчет.
Что можно сделать, чтобы избежать этой проблемы?
Это зависит от того, какие расчеты вы делаете.
blockquote>
- Если вам действительно нужны ваши результаты, чтобы точно скомпоновать, особенно когда вы работаете с деньгами: используйте специальный decimal datatype .
- Если вы просто не хотите видеть все эти дополнительные десятичные знаки: просто отформатируйте результат, округленный до фиксированного числа десятичных знаков при его отображении.
- Если у вас нет десятичных данных ype, альтернативой является работа с целыми числами, например. делать денежные расчеты целиком в центах. Но это больше работает и имеет некоторые недостатки.
Youz также может использовать «нечеткое сравнение» , чтобы определить, достаточно ли близки два числа предположим, что они будут одинаковыми с использованием точной математики.
abs($three - ($one + $two)) < $some_Very_small_number
Number :: Fraction позволяет вам работать с рациональными числами (дробями) вместо десятичных знаков, что-то вроде этого (': константы' импортируется для автоматического преобразования строк типа '11 / 10 'в Number: : Фракционные объекты):
use strict;
use warnings;
use Number::Fraction ':constants';
check_math(1, 2, 3);
check_math('11/10', '22/10', '33/10');
sub check_math {
my $one = shift;
my $two = shift;
my $three = shift;
if ($one + $two == $three) {
print "$one + $two == $three\n";
} else {
print "$one + $two != $three\n";
}
}
, который печатает:
1 + 2 == 3
11/10 + 11/5 == 33/10
Быстрый способ исправить плавающие точки - использовать bignum . Просто добавьте строку
use bignum;
в начало вашего скрипта. Очевидно, что последствия для производительности очевидны, поэтому это не может быть хорошим решением для вас.
Более локализованное решение заключается в том, чтобы явно использовать Math :: BigFloat , где вам нужна более высокая точность.
Используйте sprintf
, чтобы преобразовать переменную в форматированную строку, а затем сравнить полученную строку.
# equal( $x, $y, $d );
# compare the equality of $x and $y with precision of $d digits below the decimal point.
sub equal {
my ($x, $y, $d) = @_;
return sprintf("%.${d}g", $x) eq sprintf("%.${d}g", $y);
}
Эта проблема возникает из-за отсутствия идеального представления фиксированной точки для ваших фракций (0,1, 0,2 и т. Д.). Таким образом, значения 1.1
и 2.2
фактически хранятся как что-то вроде 1.10000000000000...1
и 2.2000000....1
, соответственно (я не уверен, что он немного больше или немного меньше. В моем примере я предполагаю, что они становятся немного больше). Когда вы добавляете их вместе, он становится 3.300000000...3
, который больше, чем 3.3
, который преобразуется в 3.300000...1
.