Как преобразовать число в один тип в perl [duplicate]

Буквально самый простой способ исправить NullReferenceExeption имеет два пути. Если у вас есть GameObject, например, с прикрепленным скриптом и переменной с именем rb (rigidbody), эта переменная начнет пустую, когда вы начнете игру. Вот почему вы получаете NullReferenceExeption, потому что на компьютере нет данных, хранящихся в этой переменной.

В качестве примера я буду использовать переменную RigidBody. Мы можем добавить данные действительно легко на самом деле несколькими способами:

  1. Добавить RigidBody к вашему объекту с помощью AddComponent> Физика> Rigidbody Затем зайдите в свой скрипт и введите rb = GetComponent<Rigidbody>();. Эта строка кода работает лучше всего под ваши функции Start() или Awake().
  2. Вы можете добавить компонент программно и назначить переменную одновременно с одной строкой кода: rb = AddComponent<RigidBody>();

Дальнейшие заметки: если вы хотите, чтобы единство добавлялось компонент для вашего объекта, и вы, возможно, забыли добавить его, вы можете ввести [RequireComponent(typeof(RigidBody))] над объявлением класса (пробел ниже всех ваших приложений). Наслаждайтесь и получайте удовольствие от игр!

9
задан brian d foy 14 October 2010 в 19:40
поделиться

8 ответов

См. Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой .

Ничто из этого не является специфичным для 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
17
ответ дан Sinan Ünür 25 August 2018 в 13:52
поделиться

Чтобы увидеть точные значения для ваших скаляров с плавающей запятой, дайте большую точность 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 отказывается печатать «несущественные» цифры.

4
ответ дан aschepler 25 August 2018 в 13:52
поделиться

«Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой»

В принципе, Perl имеет дело с числами с плавающей запятой, в то время как вы, вероятно, ожидаете, что он будет использовать фиксированные -точка. Самый простой способ справиться с этой ситуацией - изменить свой код, чтобы вы использовали целые числа везде, кроме, возможно, в финальной программе отображения. Например, если вы имеете дело с валютой доллара США, храните все суммы в долларах в гроши. 123 доллара и 45 центов становятся «12345». Таким образом, не существует неопределенности с плавающей запятой во время операций добавления и вычитания.

Если это не вариант, рассмотрите комментарий Мэтта Кейна . Найти хорошее значение epsilon и использовать его всякий раз, когда вам нужно сравнивать значения.

Я бы рискнул предположить, что большинство задач на самом деле не нужны с плавающей запятой, и я 'd настоятельно рекомендуем тщательно подумать, является ли он правильным инструментом для вашей задачи.

6
ответ дан Community 25 August 2018 в 13:52
поделиться

Из Руководство по плавающей запятой :

Почему мои цифры, например, 0,1 + 0,2, не совпадают с хорошим раундом 0,3, и вместо этого я получаю странный результат, например, 0,30000000000000004?

. Поскольку внутренне компьютеры используют формат (двоичный с плавающей запятой), который не может точно представлять число, например 0,1, 0,2 или 0,3.

Когда код скомпилирован или интерпретирован, ваш «0,1» уже округлен до ближайшего номера в этом формате, что приводит к небольшой ошибке округления даже до того, как произойдет расчет.

Что можно сделать, чтобы избежать этой проблемы?

Это зависит от того, какие расчеты вы делаете.

  • Если вам действительно нужны ваши результаты, чтобы точно скомпоновать, особенно когда вы работаете с деньгами: используйте специальный decimal datatype .
  • Если вы просто не хотите видеть все эти дополнительные десятичные знаки: просто отформатируйте результат, округленный до фиксированного числа десятичных знаков при его отображении.
  • Если у вас нет десятичных данных ype, альтернативой является работа с целыми числами, например. делать денежные расчеты целиком в центах. Но это больше работает и имеет некоторые недостатки.

Youz также может использовать «нечеткое сравнение» , чтобы определить, достаточно ли близки два числа предположим, что они будут одинаковыми с использованием точной математики.

4
ответ дан Michael Borgwardt 25 August 2018 в 13:52
поделиться

abs($three - ($one + $two)) < $some_Very_small_number

2
ответ дан mkb 25 August 2018 в 13:52
поделиться

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
1
ответ дан MkV 25 August 2018 в 13:52
поделиться

Быстрый способ исправить плавающие точки - использовать bignum . Просто добавьте строку

use bignum;

в начало вашего скрипта. Очевидно, что последствия для производительности очевидны, поэтому это не может быть хорошим решением для вас.

Более локализованное решение заключается в том, чтобы явно использовать Math :: BigFloat , где вам нужна более высокая точность.

5
ответ дан mscha 25 August 2018 в 13:52
поделиться

Используйте 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.

1
ответ дан YYC 25 August 2018 в 13:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: