Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

Explainer: Numbers

By: hoakley
6 December 2025 at 16:00

Numbers – as in maths, not Apple’s spreadsheet – were there at the dawn of computing, and have played a major part in hardware, system software and apps ever since. This article explains some of the numeric types used by your Mac, and how they can catch you out.

Numbers in computing fall into two broad classes: those represented exactly, which are mainly integers, and those normally approximated, including most floating point numbers.

Integers

These are the simplest to represent in binary and hexadecimal, and those that play the fewest tricks. They come in several varieties, determined by their size in bytes, and whether they can be negative rather than only positive. Some of us still remember when the standard integer was represented in just eight bits. The largest unsigned integer is then 1111 1111 in binary, or FF in hexadecimal, that’s 255 in regular decimal notation. If one of those bits is used to indicate whether they include negative values, they can only lie between -127 and +127.

Soon integers grew to 16 bits, then 32, and now the standard length of 64 bits, offering a range of numbers beyond our comprehension, or even the largest of distributed file systems.

Most problems that arise in integers do so from any of five causes:

  • the order of bytes, which can be ‘big-endian’ or ‘little-endian’ according to processor type and setting;
  • conversion between different lengths;
  • whether signed or unsigned;
  • overflow, in which the product of two integers requires a number larger than the maximum for their length;
  • arithmetic operations such as division, when performed by zero.

Together, these can result in quite complex errors. For example, suitably misinterpreted as a signed integer using the wrong byte order, the 32-bit unsigned integer for 65,535 (0000 FFFF) can become -2,147,418,112 (FFFF 0000).

Floating point numbers

Integers are fine for counting integral objects such as people and file sizes, but in the real world most things have to be measured in floating point or decimal numbers like 3.14159. In maths, those numbers come from a continuous range that has to include extremely large positive and negative values, and many very close to zero. They’re most familiar to us from engineering or scientific notation expressing them in terms of a number from 1.0 to almost 10.0, multiplied by a power of ten, e.g. 1.68301 x 10e-6, which is just above zero at 0.00000168301.

The most widely used form of floating point number in macOS is the Double, which uses 64 bits to encode a number using similar principles to engineering/scientific notation, only the powers used aren’t decimal but binary, making them more difficult to read and understand. In decimal notation, with the radix 10, 0.00000168301 has the significand of 1.68301 and the exponent of -6, making it 1.68301 x 10e-6. As a computer Double, the radix is 2 (binary), so it has a significand of 1.76476389376 and an exponent of -20, making it 1.76476389376e-20.

Some Doubles are exact expressions of the number they’re trying to represent. An obvious example is 1.0, represented as 1.0e0, but even fairly simple numbers like 71.3927 are confusing, with a representation of 1.1155109375e6 (radix 2). To convert between regular decimal floating point and 32- and 64-bit floating point numbers, and their hex representations, my free Mints has a Floating Point Explorer window. This is explained here.

mints1183

Unlike mathematical numbers, there’s a finite number of different Doubles, and their distribution is far from even. The same Double representing 71.39270000000000 also represents 71.39270000000001, and all the numbers in between them, all but one of which is only an approximation. Around those numbers, there are roughly 70 trillion different floating point numbers per unit (1.0) step in number. These become more dense around zero, and less dense at the extreme ends of the number line. As Doubles become larger in absolute value (disregarding their sign), so they become less precise in absolute but not relative terms.

Errors

Because they’re only approximations, Doubles suffer several problems that can adversely affect calculating with them. These include rounding and cancellation errors.

Rounding errors occur because Doubles have fixed length, so the last place has to be rounded up or down to give the best approximation to the real number. The standard for floating point (IEEE 754) specifies no less than five different rounding functions, that can result in a Double being rounded up or down. Although the relative errors from rounding should be small, they can accumulate in long series of calculations to the point where they affect overall accuracy.

Cancellation errors can be very large, even when only the result of a single operation. This term refers to potentially highly inaccurate results from subtracting numbers that are very close in value. When almost all the digits of the result are lost, these errors can be catastrophic, and may cause the order of calculations to determine the result.

These can be illustrated by two simple calculations, each of which should return a result of exactly 0.0:
((10000000.001 - 10000000.000) - 0.001) * 1.0e8
and
(10000000.001 - (10000000.000 + 0.001)) * 1.0e8
Yet using Swift Doubles, the first returns the incorrect result of 0.016391277311150754.

With a whole IEEE standard to themselves, floating point numbers have grown their own subdivision of errors and non-errors. The most commonly encountered of these is the NaN, Not a Number, which used to puzzle those plugging through spreadsheets when a formula attempted a heinous crime such as division by zero. The joy of NaNs is their propagation: once a NaN creeps into a calculation, it’s likely to turn the whole thing NaN. Then there are two different signed zeroes, +0 and -0, or if you really want a choice, why not have an unsigned zero too, and then decide whether you want all three to be equal or not.

Others

Some systems also support extended precision beyond Doubles. One of the advances brought by the first widely used maths coprocessor, Intel’s 8087, was the availability of 80-bit Extended calculations. Although valuable for some, in general, mixing precisions leads to further strange errors that can prove hard to trace. macOS tries to avoid those, and ARM processors don’t have any Extended features, which have to be implemented in additional libraries for those that need them.

Most recently, to accommodate AI using neural networks, smaller floating point numbers have become popular. bfloat16 numbers use only 16 bits of storage, but cover the same range as 32-bit floating point numbers with reduced precision. These promise huge gains in speed by allowing arithmetic instructions on twice the numbers at once, and are supported in CPUs in Apple’s M2 and later chips, and in GPUs.

You will occasionally come across other numeric formats, including fixed point and arbitrary precision. These don’t normally have any direct support in general purpose processors, but are implemented in libraries, making them considerably slower and non-transferable. And then there are arrays of numbers in vectors and matrices, complex numbers, and everything else that mathematicians have devised. There is no end.

Further reading

Start with Jean-Michel Muller et al (2018), Handbook of Floating-Point Arithmetic, 2nd ed, Birkhäuser, ISBN 978 3 319 76525 9. Then progress to Peter Kornerup and David W Matula (2010), Finite Precision Number Systems and Arithmetic, Cambridge UP, ISBN 978 0 521 76135 2. Complete the basics with Jean-Michel Muller (2006), Elementary Functions, Algorithms and Implementation, 3rd ed, Birkhäuser, ISBN 978 1 4899 7981 0. You can then progress to matrices, for which there is a huge literature.

Does that SSD Trim, and why is it important?

By: hoakley
13 November 2025 at 15:30

Trim is one of the Dark Arts of SSDs. It’s important if not essential, but it’s not easy to discover whether an SSD is Trimming properly. Some say that you need to enable Trim for external SSDs, yet others don’t and never seem to encounter a problem.

Why Trim?

Data stored on a hard disk doesn’t need to be erased before the space it takes can be reused, but SSDs work differently. Before a page of SSD memory can be reused, it must be erased, and that’s the part that takes time. If a fast SSD had to erase each page when it needed to write to it, that SSD wouldn’t be much faster than a good hard disk.

To overcome this problem, when the file system has pages that no longer contain data in use, it should tell the SSD that they’re free so they can be erased to prepare them for reuse. In SATA SSDs that’s performed by the TRIM command, and its equivalent for faster NVMe SSDs is DEALLOCATE, although it’s the older command whose name has stuck.

Modern SSDs also perform their own housekeeping, and in many cases may not need to be Trimmed at all. However, when an operating system and SSD both support Trim (or DEALLOCATE), that should ensure optimum performance.

When an SSD doesn’t get Trimmed and can’t compensate for that with its own housekeeping routines, its performance suffers noticeably. This is most commonly seen with SATA SSDs that would normally have write speeds of around 500 MB/s. When they need a good Trim, that can fall to around 100 MB/s, the same speed you’d expect from a hard disk. But this doesn’t affect read speeds at all, so one way of telling whether an SSD needs Trimming is to measure its read and write speeds.

Which SSDs are Trimmed?

You’ll be delighted to know that, for their relatively high cost, all Apple internal SSDs Trim reliably, without any need for tweaking any settings.

As a rule, external SSDs don’t Trim by default if they have a SATA interface, giving them read and write speeds of about 500 MB/s. Those with faster NVMe interfaces, including those connected by Thunderbolt 3-5 or USB4, should Trim by default when they’re formatted in APFS.

System Information normally lists a drive’s Trim support, if you can find the right section. Browse its Hardware section to discover the protocols the drive supports. These can be confusing, as the SSD and its enclosure may well have multiple entries in different headings, and some of the information may appear conflicting.

trim01

USB4 drives operating in Thunderbolt 3 mode can also be confusing. When connected to an Intel Mac (which doesn’t support USB4 itself) they may be reported in the Thunderbolt/USB4 device tree as being USB4.0 operating in Thunderbolt 3 mode, with a link speed of up to 40 Gbit/s, then in the NVMExpress device tree with a link width of x4 and speed of 8.0 GT/s.

SATA drives should appear in the Serial-ATA device tree, even though they might be connected via Thunderbolt 3, and you may see a statement of Trim support.

trim02

Device trees worth inspecting include: NVMExpress, PCI, SATA, Storage, Thunderbolt/USB4 and USB.

Which file systems Trim?

Trim is well-demonstrated in SSDs formatted in APFS, and is known to occur in HFS+. However, old PC files systems like ExFAT don’t have any Trim support, and it can’t be enabled in a Mac at least.

Unfortunately, as HFS+ is now an old Mac filesystem, it can’t readily be seen in log entries, while those from APFS contain valuable detail that makes them suitable for use when testing for Trim.

How to verify Trim

Use Mints to verify whether your external drive does get trimmed correctly when it’s mounted, using its Disk Mount feature. In essence, what you do is:

  1. Eject and disconnect the external drive.
  2. Connect the drive at a known time, according to the Mac’s clock.
  3. Leave the Mac alone until all that disk’s volumes have been mounted.
  4. 20 seconds after connecting the drive, or 10 seconds after the last of its volumes has mounted, open the Mints app.
  5. Click on the Disk Mount button, and set the time in its log window to the time at which you connected the drive.
  6. Set the period to a minimum of 20 seconds, long enough to cover the period up to 10 seconds after the last volume mounted.
  7. Uncheck all the category checkboxes except the first, APFS +.
  8. Click the Get log button.
  9. When log entries are displayed, scroll to the end and look back for APFS trim entries.

This only works for APFS, though, as log entries for HFS+ don’t appear to show Trimming in this way.

trim05

Those entries are characteristically of the form
23-03-25 19:01:06.930 apfs spaceman_scan_free_blocks:3311: disk5 scan took 0.030901 s (no trims)
23-03-25 19:01:10.960 apfs spaceman_scan_free_blocks:3293: disk5 scan took 4.030544 s, trims took 3.944665 s
23-03-25 19:01:10.960 apfs spaceman_scan_free_blocks:3295: disk5 471965989 blocks free in 9131 extents
23-03-25 19:01:10.960 apfs spaceman_scan_free_blocks:3303: disk5 471965989 blocks trimmed in 9131 extents (432 us/trim, 2314 trims/s)
23-03-25 19:01:10.960 apfs spaceman_scan_free_blocks:3306: disk5 trim distribution 1:1461 2+:1267 4+:4121 16+:785 64+:822 256+:675

trim06

Check that the named disk, here disk5, is the SSD or APFS container on the SSD that you’re checking. If it has entries reporting that blocks have been trimmed, this confirms that the SSD has been trimmed as expected. Disks that don’t trim normally only show the first of that series, ending in the words no trims.

It’s possible to enable Trim for all external storage using the trimforce command, but you should normally verify that your external SSD does Trim correctly when mounted.

If you have an SSD that hasn’t been Trimming and is suffering poor write performance, you may be able to help it recover by copying its contents to another disk, then erasing its volumes, or the whole container. Those should return their whole contents as free space, and so enable the SSD’s own housekeeping to erase them in readiness for reuse.

Inside the Unified Log 5: Navigation

By: hoakley
14 October 2025 at 14:30

The greatest challenge in using the Unified log is how to navigate its many thousands of entries, to find those you want to read. Success depends on the combination of two aids: time and waypoints (or landmarks).

Time

No matter how you obtain log extracts, you need to know when to look for those entries. The more precisely you can work out the time of interest, the quicker and easier it will be to locate the entries you’re interested in. While the log command offers alternatives, LogUI works throughout using the local time applicable when you access the log, allowing for your current time zone and any seasonal adjustment to it, when accessing the live log in that Mac.

However, the underlying times given in log extracts are those recorded by the Mac or device whose log you’re accessing. If its system clock was five minutes slow when those entries were written to its log, then you need to allow for that. For example, when I first started my Mac yesterday its clock might have been 1 minute slow. An event that occurred at 10:56 yesterday by the room clock would therefore appear in the log entries for 10:55.

One important time you can discover is the boot time of the Mac. Mints offers a Boot button to retrieve boot times over the last 24 hours. If the logs were written by a different Mac or device, then you’ll need to search for the time of that last boot. Fortunately the first two log entries are easily recognised:
11:41:37.562774+0100 === system boot: D3CEA9B4-F045-434D-8D12-C6E794A02F14
11:41:42.758780+0100 kprintf initialized

The long gap between the first two entries is accounted for by the firmware phase of the boot process. If necessary you can search for a message containing === (three equals signs). Mints provides the time of the first of those for each boot, and its UUID.

There are two occasions when time can become confusing, when clock corrections are applied, and when clocks are moved forward or back to add or remove summer or seasonal time changes. Fortunately the latter only change twice each year, although when they do, you really don’t want to see what happened in the log, and those changes aren’t even applied at a predictable time.

Clock corrections, like kernel boot, are readily found by the === text in their message. They normally happen in pairs, with the first correction the larger, and the second often far smaller. Here’s an example seen in consecutive log entries:
08:26:16.140474+0100 /usr/libexec/sandboxd[80] ==> com.apple.sandboxd
08:26:10.043353+0100 === system wallclock time adjusted
08:26:10.044335+0100 Sandbox: distnoted(72) deny(1) file-read-metadata /private
08:26:10.044601+0100 2 duplicate reports for Sandbox: distnoted(72) deny(1) file-read-metadata /private
08:26:10.044606+0100 Sandbox: distnoted(72) deny(1) file-read-metadata /Library
08:26:10.089204+0100 === system wallclock time adjusted
08:26:10.091850+0100 started normally

The first adjustment dropped the clock back by 6.1 seconds, from 08:26:16.140474 to 08:26:10.043353. This means that you’ll see times of 08:26:12 both before the correction and afterwards. The second adjustment, from 08:26:10.044606 to 08:26:10.089204, was far smaller at 0.045 seconds, and at least went in the right direction.

The most substantial clock corrections are made shortly after booting. Although macOS does make them later, the size of those should be smaller.

Waypoints

Even working with times resolved to the second, those can still leave you browsing thousands of log entries. To locate more precisely you need details of one or more entries that will be sufficiently distinctive to focus in on a few dozen. These are waypoints for navigation.

LogUI provides three methods for locating these waypoints:

  • using a search predicate to determine which log entries are extracted from the log;
  • applying search text to filter out all entries that don’t contain a term;
  • searching a rich text export of the log extract.
Predicates

These are best used when the time period of your extract needs to be relatively long, so would return a large number of entries. For example, if you can only narrow the time down to several minutes, and are looking for the time that a specific app was launched, you can look for that app’s job description when it’s created and written to the log by RunningBoard.*

Over a period of two minutes, RunningBoard might write thousands of entries in the log, so looking for your app’s job description among them would be time-consuming. Set the start time and period to cover the whole of the time you want to search, then set a predicate for the subsystem com.apple.runningboard.

When LogUI fetches that log extract, there might still be over 2,000 entries, so now is the time to apply search text to filter those further.

Search filter

To filter those 2,000 entries and show only those containing job descriptions created by RunningBoard, enter the text constructed job in LogUI’s search box, with its menu set to Messages, and press Return. You’ll now see that list reduced to just a handful, and looking through them you can discover exactly when your waypoint occurred.

My example for this article starts with a period of just 2 minutes, in which there were more than 100,000 log entries.

Using the com.apple.runningboard predicate whittled those down to 13,443 entries.

Searching within those for constructed job left me with just 8 entries to look through.

Search rich text

Sometimes you can’t devise the right combination of predicate and search filter to discover what you’re looking for, which might be an error reported in a subsystem or a process that you can’t identify. One good way forward is to narrow your log extract as much as you can, then save the extract as Rich Text, open that in a suitable editor, and search through it for the word error. That will discover every log entry containing the word error anywhere, rather than confining it to the message text.

Using time and waypoints

Armed with your waypoint and the exact time of its entry in the log, you can now set that as the start time, set a period of a couple of seconds, and get a full log extract containing all the detail you might need. This should give you further clues to allow you to move through time using predicates and search filters to discover what happened. This is much quicker and less frustrating than trying to scan through thousands of log entries in search of vague clues.

Key points

  • Use time and waypoints to find log entries.
  • Mints’ Boot button gives times of each boot in the last 24 hours.
  • Reduce the number of log entries returned using a predicate.
  • Narrow those down using a search filter.
  • Search all text by exporting the log extract as Rich Text.

* Sadly, the days of being able to access freely RunningBoard’s informative job descriptions in the log are over. As of macOS Tahoe, all you’ll see is the dreaded <private> of censorship. If you want to examine these now, you’ll have to remove log privacy protection first. Thanks, Apple, for providing such useful tools then rendering them next to useless.

Resolve a file’s path from its inode number

By: hoakley
8 October 2025 at 14:30

If you ever encounter an error when checking an APFS volume using First Aid in Disk Utility or fsck_apfs, you won’t be informed of the path and name of the item responsible, but given its inode number, in an entry like
warning: inode (id 402194151): Resource Fork xattr is missing for compressed file

The inode number given can only be resolved to a path and file/folder name if you also have a second number giving the volume for that item. As that will be for the volume being checked at the time, you should be able to identify that immediately. The only time that you might struggle to do that is with items in a snapshot; those should, I think, be the same as the volume they are taken from. However, as snapshots are read-only, there’s probably little point in pursuing errors in them.

To resolve these in my free utility Mints, open its inode Resolver using the Window / Data… / Inode menu command. Drag and drop another file from the same volume onto that window.

mints1151

The Resolver will then display that file’s volfs path, such as
/.vol/16777242/1241014

All you need do now is paste the inode number given in the warning or error message in Disk Utility or fsck_apfs, into the Inode Number box at the top of the Resolver window, and click the Resolve button. Mints then looks up information for that inode number on the same volume, using GetFileInfo, and displays it below.

mints1152

One drag and drop, a paste, and a click to discover what APFS is complaining about.

Command line

You’ll sometimes see Terminal’s find command with the option -inum recommended as a way to convert from an inode number to a regular path. Although you can do that, it’s easier to use the command GetFileInfo instead. For that you’ll need the full volfs path, including the volume number.

To find the volume number, use my free utility Precize, and open another file on the same volume. The second line in its window gives the full volfs path for that file. Copy the start of that, leaving the second number, the inode, such as
/.vol/16777238/

purgeable1

Alternatively, you can use the stat command as given below.

In Terminal, type
GetFileInfo
with a space at the end, and paste the text you copied from Precize. Then copy and paste the inode number given in the First Aid warning, to assemble the whole command, such as
GetFileInfo /.vol/16777238/402194151

Press Return, and after a few seconds, you should see something like
file: "/Users/hoakley/Library/Mobile Documents/com~apple~CloudDocs/backup1/0MintsSpotlightTest4syzFiles/SpotTestA.rtf"
type: "\0\0\0\0"
creator: "\0\0\0\0"
attributes: avbstclinmedz
created: 05/17/2023 08:45:00
modified: 05/17/2023 08:45:00

giving the full path and filename that you want.

GetFileInfo is one of the oldest commands in macOS, and has been deprecated as long as anyone can remember. I suspect that Apple is still trying to work out what can substitute for it.

Get a volfs path for a file

Use Precize to run this the other way around: open the file and read the path in that second line. To copy the whole of it, press Command-2.

The simplest ways of obtaining inode numbers and so building volfs paths in Terminal are using the -i option to the ls command, and for individual items using stat:
ls -i lists each item in the current directory, giving its inode number first, e.g.
22084095 00swift
13679656 Microsoft User Data
22075835 Wolfram Mathematica

and so on;
stat myfile.text returns
16777220 36849933 -rw-r--r-- 1 hoakley staff […] myfile.text
where the first number is the volume number, and the second is the inode number of that item, or /.vol/16777220/36849933.

❌
❌