Подсчитать масштаб данного десятичного числа - PullRequest
2 голосов
/ 29 октября 2019

Как я могу посчитать масштаб данного десятичного числа в Powershell?

$a = 0.0001
$b = 0.000001

Приведение $a к строке и возврат $a.Length дает результат 6 ... Мне нужно 4.

Я думал, что будет десятичная или математическая функция, но я не нашел ее, и путаница со строкой кажется не элегантной.

Ответы [ 2 ]

3 голосов
/ 29 октября 2019

Возможно, есть лучший математический способ, но я бы нашел такие десятичные знаки, как это:

$a = 0.0001
$decimalPlaces = ("$a" -split '\.')[-1].TrimEnd('0').Length

По сути, разделите строку на символ . и получите длину последней строки вмассив. Обтекание $a в двойных кавычках неявно вызывает .ToString() с инвариантной культурой (вы могли бы расширить это как $a.ToString([CultureInfo]::InvariantCulture)), делая этот метод для определения количества десятичных знаков культурно-инвариантным.

.TrimEnd('0') используется в том случае, если $a получены из строки, а не с правильным типом числа, возможно, что можно включить конечные нули, которые не должны считаться десятичными разрядами. Однако, если вам нужна шкала , а не только используемые десятичные разряды, оставьте .TrimEnd('0') отключенным, например, так:

$decimalPlaces = ("$a" -split '\.')[-1].Length
2 голосов
/ 30 октября 2019

mclayton полезно связан с этим ответом на связанный вопрос C # в комментарии, и решение там действительно может быть адаптировано к PowerShell, при работе с или преобразовании вдопустим тип [decimal] :

# Define $a as a [decimal] literal (suffix 'd')
# This internally records the scale (number of decimal places) as specified.
$a = 0.0001d 

# [decimal]::GetBits() allows extraction of the scale from the
# the internal representation:
[decimal]::GetBits($a)[-1] -shr 16 -band 0xFF # -> 4, the number of decimal places

Метод System.Decimal.GetBits возвращает массив внутренних битовых полей, последний элемент которых содержит шкалу в битах 16 -23 (8 бит, даже если максимальный допустимый масштаб равен 28), что и указано выше.

Примечание. Литерал числа PowerShell, являющийся дробным числом без суффикс d - например, 0.0001 становится экземпляром [double], т. Е. двоичное число с плавающей точкой двойной точности.

PowerShell автоматически преобразует [double] в[decimal] значения по запросу, но обратите внимание, что могут быть ошибки округления из-за различных внутренних представлений, и что [double] может хранить большие числа, чем [decimal] может (хотя и не точно).

A[decimal] буквально - вклe с суффиксом d (обратите внимание, что в C # используется суффикс m) - анализируется со шкалой в точности так, как указано , так что применение выше к 0.000dи 0.010d дает 3 в обоих случаях;то есть конечные нули являются значимыми .

Это не применяется, если вы (неявно) конвертируете из [double] экземпляров, таких как0.000 и 0.010, для которых приведенное выше дает 0 и 2 соответственно.


A строка решение на основе :

Чтобы предложить более краткую (также культурно-инвариантную) альтернативу Полезный ответ Бендера Величайшего :

$a = 0.0001
("$a" -replace '.+\.').Length # -> 4, the number of decimal places

Предостережение : Это решениеполагается на строковое представление по умолчанию числа [double], которое не обязательно должно соответствовать исходному формату ввода;например, .0100, если позже будет преобразовано в строку, становится '0.01';однако, как обсуждалось выше, вы можете сохранить конечные нули, если начнете с литерала [decimal]: .0100d преобразуется в '0.0100' (сохранено количество введенных десятичных знаков).

  • "$a", использует расширяемую строку (строковая интерполяция PowerShell) для создания культурально-инвариантного строкового представления числа, чтобы гарантировать, что строковое представление использует . в качестве десятичного числаmark.

    • По сути, PowerShell вызывает $a.ToString([cultureinfo]::InvariantCulture) за кулисами. [1] .

    • Для контраста, .ToString() (без аргументов) применяет правила текущей культуры , а в некоторых культурах в качестве десятичной отметки используется , - не . -

    • Предостережение : Если вы используете просто $a в качестве LHS -replace, $a является неявно стратифицированным, в этом случае вы - с любопытством- получить культуру- чувствительное поведение, как с .ToString() - см. этот выпуск GitHub .

  • -replace '.+\.' эффективно удаляет все символы до и включая десятичную точку из входной строки, а .Length подсчитывает символы в результирующей строке - количество десятичных знаков.


[1] Обратите внимание, что откачивает из строк в PowerShell, также используют инвариантную культуру (фактически, вызывается ::Parse($value, [cultureinfo]::InvariantCulture)), так что длядля разбора строкового представления culture-local вам необходимо явно использовать метод ::Parse();например, [double]::Parse('1,2'), а не [double] '1,2'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...