'inf' в awk работает не так, как '-inf'

Похоже, safecopy — это то, что вы ищете.

safecopy tries to get as much data from SOURCE as possible, even resorting to device specific low level operations if applicable.

8
04.05.2020, 18:37
2 ответа

Реальная задача лучше всего решается путем инициализации ваших максимальных/минимальных значений не воображаемым «наименьшим» или «наибольшим» числом (, которое может быть не реализовано в используемой вами среде. используя, в данном случае awk), но инициализируя его, используя фактические данные. Таким образом, всегда гарантирован значимый результат.

В вашем случае вы можете использовать самое первое значение, которое вы встретите (, то есть запись в первой строке )для инициализации maxи minсоответственно, добавив правило

NR==1{min=$1}

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

NR==1{max=min=$1}

Что касается причины, по которой ваш подход с infне работал с awk, тогда как -inf, казалось, работал, @steeldriver дал хорошее объяснение в комментарии к вашему вопросу, который я также резюмировать для полноты:

  • В awkпеременные имеют "динамический тип", т.е.все может быть строкой или числом в зависимости от использования (, но awk«запомнит», как оно использовалось в последний раз, и сохранит эту информацию для использования в следующей операции ).
  • Всякий раз, когда в коде обнаруживаются арифметические операции с участием переменной, awkпопытается интерпретировать содержимое этой переменной как число и выполнить операцию, с которой переменная вводится как числовая в случае успеха.
  • Значением по умолчанию для любой переменной, которой еще ничего не присвоено, является пустая строка, которая интерпретируется как 0 в арифметических операциях.
  • Имя переменной (*)infне имеет специального значения в awk, поэтому при использовании именно так это пустая переменная, которая будет равна 0 в арифметическом выражении, таком как -inf. Следовательно, «максимальный поиск» с переменной max, инициализированной значением -inf, работает, если все ваши данные положительны, потому что -inf— это просто 0 (и, таким образом, наименьшее не-отрицательное число ). ].
  • Однако в задаче «минимального поиска» инициализация minзначением infприведет к инициализации переменной пустой строкой, поскольку отсутствует арифметическая операция, которая гарантировала бы автоматическое преобразование этой пустой строки в число.
  • Поэтому в более поздних сравнениях

    if ($1<min) min=$1
    

    ввод, $1, сравнивается со строковым значением, поэтому awkтакже обрабатывает $1как строку и выполняет лексикографическое сравнение, а не числовое.

  • Однако с лексикографической точки зрения нет ничего "меньше", чем пустая строка, и поэтомуminникогда не присваивается новое значение. Поэтому в разделе ENDутверждение

    print min
    

    печатает (по-прежнему )пустую строку.

(*)см. ответ Стивена Китта о том, как строка с содержимым"inf"может иметь значение в awk.

17
28.04.2021, 23:16

Ваш подход не работает, потому что infне имеет особого значения в GNU AWK в режиме по умолчанию, отличном от -POSIX. В результате оно интерпретируется как имя переменной, и, поскольку переменной ничего не присвоено, ее значение равно 0 в арифметическом контексте и пустой строке в строковом контексте. Таким образом, ваш код найдет максимальное значение, только если оно положительное (, поскольку maxинициализируется в арифметическом контексте ), и не найдет минимальное значение (, поскольку minинициализируется в строковом контексте. ); подробности см. в ответе AdminBee .

Чтобы определить минимальное и/или максимальное значение в файле (или потоке ), следует следовать советам, данным в ответе AdminBee .

Однако, если вы используете GNU AWK, вы можете вычислить log(0), чтобы инициализировать ваши переменные положительной или отрицательной бесконечностью, и использовать это аналогично вашему подходу:

BEGIN { max = log(0) }
$1 > max { max = $1 }
END { print max }
BEGIN { min = -log(0) }
$1 < min { min = $1 }
END { print min}

Единственное преимущество этого подхода по сравнению с инициализацией значений из первой строки заключается в том, что он обеспечивает отличительные результаты, когда никакие значения не обрабатываются — положительная или отрицательная бесконечность в конечном итоге являются надежными индикаторами того, что значение не было замечено. (Существуют и другие способы определить это, в том числе проверка на наличие пустой строки, а не 0 при инициализации с первой строки.)

С GNU AWK в режиме POSIX(POSIXLY_CORRECT=1)или другими интерпретаторами AWK, совместимыми с POSIX -, такими как mawk, предоставление "inf"в виде строки в арифметическом контексте дает бесконечность,благодаряstrtod:

BEGIN { max = "-inf" + 0 }
$1 > max { max = $1 }
END { print max }
BEGIN { min = "+inf" + 0 }
$1 < min { min = $1 }
END { print min}
13
28.04.2021, 23:16

Теги

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