View Single Post
Old 2019-11-12, 23:07   #9
Dylan14
 
Dylan14's Avatar
 
"Dylan"
Mar 2017

11128 Posts
Default The format command

Do you know that in a lot of programs one can change how things are formatted? For example, many word processors (including the WYSIWYG editor that I am using to type this part of the tutorial) have many options available to change how text looks, such as font size, color and alignment. In programming, this isn't what we are referring to, but rather how things are presented to the end user. This can be seen in various programs that are used on Mersenneforum and elsewhere.

A teaser: a look at mfaktc's PrintFormat option(*):

Mfaktc has several options available to influence how it operates. Most of the options affect the usage of the GPU, but there is an option in the ini file to adjust what it prints on the screen when it completes a class. This option is called "PrintFormat". I won't go through the full options (refer to the threads linked, or in your instance of mfaktc), but we'll look at a few of the options.
First, we'll look at %t, which is the option for the time elapsed per class. There are four ways it can be printed, depending on the number that needs to be displayed: "%6.0f" (no decimal places), "%6.1f" (1 decimal place), "%6.2f" (2 decimal places), or "%6.3f" (3 decimal places). These will display up to 6 digits.
As another example, we can look at %M, the exponent. This is a number which can be up to 10 decimal digits (as the exponent limit of mfaktx is 2^32-1). This is expressed in the format string, "%-10u".
The rest should make more sense after we go through how Python handles string formatting.

Python's format command:

The format command is part of the core language, in the string.py file. The syntax is the following:

Code:
{}.format(string_to_be_formatted, /, args, kargs)
As a simple example, we will consider a substitution of text in the format:

Code:
print("mersenneforum likes the following program: {}".format("Prime95"))
This yields the following string:

Code:
mersenneforum likes the following program: Prime95
As we can see, python inserted the text Prime95 in the space marked by the curly brackets. Now, of course, we can specify multiple sets of curly brackets, and when we do that, Python will substitute those in. In modern versions of Python (**), you don't need to specify positional arguments in the format command, meaning the following are equivalent:

Code:
'{} and {}'.format("spam", "eggs")
Code:
'{0} and {1}'.format("spam", "eggs")
Both yield the string, 'spam and eggs'. By changing the numbers instead to 1 and 0, we get 'eggs and spam'. So if the positional arguments are not set, then they will be in the order that you specify them in the format command.

Do note, that if you do specify positional arguments but you index a non-existent entry (say, by typing in a 2 instead of 0 in our example), you will get an IndexError.

Formatting numbers:

So now that we have handled text, how do we handle numbers in our format command?

In python, we have several options on how we can handle numbers. These are
'e' - print the number in exponent notation, using e to indicate the exponent.
'E' - same as e, but use E instead.
'f' - displays a number as a fixed point number.
'F' - same as 'f' but nan (not a number) is displayed as NAN and inf (infinity) is displayed as INF.
'g' - general format. For a given precision >=1, round the number to p significant figures and then format using 'f' or 'e' depending on the magnitude of the number. +/-infinity, +/-0 and not a number is formatted as inf, -inf, 0, -0 and nan. (***)
'G' - similar to g but use E if the number is too large. Also capitalizes inf and nan.
'n' - uses the current locale to insert the appropriate number separator characters, but otherwise the same as g.
'%' - percentage.
none - similar to 'g' but when fixed point notation is used the number has at least one digit past the decimal point.

Simple example: truncating pi

As we all know, pi is approximately 3.14159265358979323846... . However, this takes up a lot of space. Let's make it 5 decimal places long:

Code:
pidecimaldigits = 3.14159265358979323846
print("{:.5f}".format(pidecimaldigits))
This yields the number 3.14159.

Returning to mfaktc - reproducing the format of a progress indicator

Armed with our knowledge, we can reproduce the progress line in mfaktc in Python.
Let's reproduce a simple line, with class, time, rate:
Code:
Class = 348
time = 21.824
rate = 912.1
print("Class: {0}/4620, time: {1:.2f} s, GhZ-d/day: {2:.2f}".format(str(Class), time, rate))
This yields the following:

Code:
Class: 348/4620, time: 21.82 s, GhZ-d/day: 912.10
(*) The options should be similar in the OpenCL equivalent, mfakto, as well as the Double Mersenne program, mmff. More information can be found here, or here.
(**) Applies for version 3.1+. In 3.4+ they can also be omitted for the Formatter, which is the class that contains the format command.
(***) More precise rules can be found at https://docs.python.org/3/library/st...-mini-language.

Last fiddled with by Dylan14 on 2020-04-14 at 21:30 Reason: initial draft
Dylan14 is offline