The Issue

Mikhail considered the case of setting a frame width to (exactly) 12.75in:

The entered width of this frame is 12.75 inches.

Now, right-clicking the horizontal ruler and changing the measurement unit to “Ciceros”,

Changing to ciceros…

you get the value 71c9.441 in typographic notation (which means 71+9.441/12 in decimal notation.)

The approximated width, in ciceros, according to InDesign.

So, according to InDesign, 12.75in ≈ 71c9.441. The symbol accounts for the approximation.

Note. — InDesign's display precision is 1/10,000 up to 4 decimal points, and all measurements are internally coerced into PostScript points. See “Precision of HurryCover Measurements” for a more detailed discussion on this topic.

However, Mikhail's original ExtendScript code produced a slightly different result (71c9.5866), which deviates from the displayed value by +0c0.1456, that is, +0.0121 ci in decimal notation. This really is a tiny difference—something like 55 µm—but Mikhail wanted to explain the gap and improve his script. Most InDesign users aren't familiar with rounding errors, so they may visually consider 71c9.5866 as a wrong value compared to 71c9.441. In fact, they differ only by the size of three neurons!

In the previous version of the SizeInUnitsEng.jsx script, the general strategy was to apply an Adobe-to-French-Points conversion when dealing with ciceros. For that purpose, the factor 3528/3759, or similarly 254/271 was used, based on the fact that “French inch has size 27.1 mm [resp. French point is 0.3759 mm]; while Adobe inch is 25.4 mm long [resp. Abobe point is 0.3528 mm].”

Also, it was assumed that UnitValue's metric accurately reflects those ratios… which didn't appear to be the case at all!

So, What Is a Cicero?

• According to wikipedia FR, one cicero is 12 Didot points, that is:

    1 ci ≈ 4.512 mm.

(The symbol is very important here, as the definition of the “point” itself varied across History, as well as the “French inch”.)

• According to wikipedia EN, a better estimation of the cicero (“1/6 of the historical French inch”) would be:

    1 ci ≈ 4.51165812456 mm.

• According to InDesign's display, 1000 ciceros equals 4511.278 mm, so:

    1 ci ≈ 4.511278 mm.

• Finally, according to the UnitValue class implemented in InDesign/ExtendScript,

    1 ci ≈ 4.51104 mm,

so we clearly get an uncertainty from the 4th decimal place when dealing with millimeters.

Regarding inches, it's worth mentioning that InDesign display is altered by rounding errors as well, so it may appear that it doesn't even comply with its own rules in some cases. Just consider the 12.75in example above:

    12.75 in ≈ 71c9.441  (ID display.)

Now, in Adobe metrics, we have two known facts:

    (a) 1 in = 72pt (Adobe measurements.)

    (b) 1 ci = 12.7872pt (straight from UnitValue.)

From (a), 12.75in = 918pt;
from (b), 10000ci = 127872pt,
which leads to the following conversion table:

Manual conversion of 12.75 inches into ciceros (x).

It comes 12.75 inches = (71 + 117/148) ciceros. The decimal part expressed in 12th gives 351/37 (≈ 9.486486486), so the best approximation we can write is:

    12.75 in ≈ 71c9.4865 (our result — vs. 71c9.441 from ID.)

So, according to our own calculations, InDesign's display is “wrong” by about +0c0.04. Still a microscopic error!

Choose your Factor!

As a matter of fact, we don't know with a sufficient accuracy the internal factor that UnitValue uses when it converts from ciceros. However, since it is considered that 1 cicero should equal “12 French points”, the best offer we can provide from the UnitValue perspective is:

    const K = 12/(UnitValue("1ci").as("pt")); // 0.93843843843844

The value of K falls between 254/271 (≈0.937269373) and 3528/3759 (≈0.938547486) mentioned earlier. There are good reasons to suppose it will bring more consistent results.

Here is a sample script that you can use for testing this approach:

 
// Proposed factor when using intermediate
// conversion to points (French vs. Adobe.)
// ---
const K = 12/(UnitValue("1ci").as("pt"));
 
// Input parameters
// ---
var inputString = "12.75";
var inputUnit = "in";
 
// Rounding param.
// ---
var round = 4;
 
// Conversion.
// ---
var sizeAsAbobePt = UnitValue(inputString, inputUnit).as("pt");
var sizeAsFrenchPt = sizeAsAbobePt*K;
 
floatResult = parseFloat(sizeAsFrenchPt/12);
intResult   = parseInt(sizeAsFrenchPt/12);
 
// Refine the frac. part (typographic notation.)
// ---
diff = floatResult - intResult;
frac12 = (diff*12).toFixed(round);
 
// Output.
// ---
alert( intResult + "c" + frac12 );  // 71c9.4865
 

This leads to a very decent approximation (71c9.4865) although InDesign still displays different digits (71c9.441) that anyway diverge from the theoretical result.

Note. — Don't be surprised if you observe differences at the 2nd or 3rd position after the decimal point in a fraction that itself represents how many 12th of the cicero unit we should take! The disagreement between 71c9.49 and 71c9.44 is, in fact, anecdotal. Since K is uncertain from the third decimal place, 10*K is uncertain from the 2nd decimal place, 100*K is uncertain from the 1st decimal place, and so on. In our particular example, sizeAsAbobePt is about 918 (in pt), which may even generate a bigger error. If we had used K=254/271, the final result would have been 71c8.4133! And I do not mention the additional rounding errors introduced by floating-point arithmetic (multiplications and especially divisions.)

A More Direct Solution

But, to me, there was still a mystery in Mikhail's algorithm: why on earth would the Adobe-to-French points translation have to be processed?

Indeed, is there anything wrong in just invoking UnitValue(input).as("ci")?

Here is the simple code I've tested while investigating the issue:

var v = UnitValue("12.75in").as("ci");
// => 71.7905405405405 ; exact: 71 + 117/148.
 
// Convert decimal notation into typographic notation `#c#.#`
// ---
var n = parseInt(v,10); // Integer part: 71
 
var d12 = 12*(v-n);     // Dec. part × 12
// => 9.4864864864864 (exact: 351/37.)
 
12 <= d12 && (++n, d12-=12); // Who knows?
var result = n + 'c' + d12;
 
alert( result );
// => 71c9.4864864864864
 

Without a shadow of a doubt, this is the closest value to the theoretical result (71c9.4865) ever obtained. The reason is, almost all intermediate multiplications and divisions have been avoided, the core computation being just performed by UnitValue's internal processor.

Conclusion: if you use its native routines properly, ExtendScript can be more accurate and reliable than InDesign itself ;-)


Related links:

• Measurements and Explanations: Educational material about ratios of printing sizes, by Mikhail Ivanyushin;
• Associated Scriptopedia entry;
IdExtenso::Units, a consistent facade for handling metrical units.