Подсчитайте масштаб данного десятичного знака

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

$a = 0.0001
$b = 0.000001

Кастинг $a к строке и возвращение $a.Length дает результат 6... мне нужно 4.

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

2 ответа

Решение

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

$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

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] может (хотя и не совсем точно).

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

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


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

Чтобы предложить более сжатую (также инвариантную к культуре) альтернативу полезному ответу Bender The Greatest:

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

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

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

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

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

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

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


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

Другие вопросы по тегам