jfbu / texdimens

Utilities and documentation related to TeX dimensional units
1 stars 0 forks source link

Add `\texdimenbothbpmm` and friends for conversions between `bp` and `mm`? #10

Closed RuixiZhang42 closed 2 years ago

RuixiZhang42 commented 2 years ago

Motivation

The motivation of this issue largely comes from CJK (Chinese/Japanese/Korean) typography traditions.

The “large” units (in and cm) are good for describing page elements, but they are too crude when it comes to describing text elements (such as font size). The Japanese Industrial Standard JIS X 4051 defines the unit “Q” to be used when specifying font sizes (it also defines PostScript point bp). One “Q” is a quarter of a millimeter (0.25mm), and 13Q=3.25mm body text (about 9.247 TeX points) is quite commonly used in Japanese publications. Similarly, the China National Standard GB/T 18358-2009 (recommended/non-mandatory) defines various text/page elements based on either mm or bp unit.

Thus, it would be nice to provide \texdimenbothbpmm, \texdimenbothmmbp, etc., to give maximal dimension not exceeding the original input while being attainable in both mm and bp units.

My research so far

As proven and documented, for in and cm, the attainable Usp has the form U=floor(a*7227/100)=floor(b*7227/254), where a=50*k and b=127*k for some common integer k (nonnegative). Any other a=50*k+r (r=1..49) or b=127*k+r (r=1..126) will lead to a Usp which is not attainable in the other unit.

The situation is different (and far more complicated) for bp and mm though. I started by looking at inputs in mm unit, so X=floor(a*7227/2540) for some a=2540*k+r (r=0..2539). Since the behavior of X is periodic (mod 2540), we can focus on a=0..2539 only. Now the question is whether this X is attainable from bp or not.

We know X is not attainable from bp if and only if X=267, 535, or 802 (mod 803). We can then brute force through a=0..2539 to see which a leads to one of these three unattainable values.

(* Xsp is input via mm, but unattainable via bp because Mod[X,803]==267 *)
Total[
 Table[
  If[Mod[Floor[a 7227/2540], 803] == 267, 1, 0],
  {a, 0, 2540 - 1}
  ]
 ]
(* gives 3 *)
(* X=Floor[(2540*k+r)*7227/2540], r=94, 1223, or 1505 *)

(* Xsp is input via mm, but unattainable via bp because Mod[X,803]==535 *)
Total[
 Table[
  If[Mod[Floor[a 7227/2540], 803] == 535, 1, 0],
  {a, 0, 2540 - 1}
  ]
 ]
(* gives 3 *)
(* X=Floor[(2540*k+r)*7227/2540], r=1035, 1317, or 2446 *)

(* Xsp is input via mm, but unattainable via bp because Mod[X,803]==802 *)
Total[
 Table[
  If[Mod[Floor[a 7227/2540], 803] == 802, 1, 0],
  {a, 0, 2540 - 1}
  ]
 ]
(* gives 3 *)
(* X=Floor[(2540*k+r)*7227/2540], r=282, 1411, or 1693 *)

Exactly 9 inputs of a (out of every span of 2540 integers) lead to unattainable Xsp in bp unit; they are a=2540*k+r, where r=94282, 1035, 1223, 1317, 1411, 1505, 1693, and 2446.

So the algorithm for \texdimenbothmmbp seems straightforward:

  1. get a;
  2. test if a=94282, 1035, 1223, 1317, 1411, 1505, 1693, or 2446 (mod 2540).
  3. if not, leave a as is.
  4. if yes, a := a-1.
jfbu commented 2 years ago

The situation is more complicated indeed than for in and cm. I need to ponder your proposal there is something I don't see, but it is too late here, I must sleep.

edit: you can skip most of my chatter here and jump to last line

As I did not see an obvious analytical way, I see a dumber way: very few dimensions are not expressible in bp, only 3 out of very chunk of 803. So start from \texdimenmmdown{N sp} or rather get from its internals the integera such that M = floor(a*7227/2540) is largest one smaller than N. We have 800 chances out of 803 that it will be exactly expressible in bp unit, which we can check by testing M modulo 803 (I must sleep so I don't search now the 3 gaps, maybe they are in your comment). If we are unlucky, replace a by a-1 and check again. In at most 4 steps (here I would need to know the gaps to tell better) we can not have been unlucky systematically (maybe only two steps) because decreasing a by 1 will only decrease M by 2 or 3 and we can not hit 4 gaps in such a short stretch which are all distinct modulo 803. Now probably it is much better still because the gaps are probably at 803/3 distance from one another... oh well let's get them

>>> S=set((n*803)//800 for n in range(800));
>>> T=set(n for n in range(803));
>>> print(T-S);
{802, 267, 535}

so no it's trivial: we only have to do a->a-1 once. Either it works for a or it will work for a-1.

So for algorithm it looks easy, but analytically with a formula like the one for both in and cm ... looks indeed more difficult, but this another matter.

Thanks as clearly I need to add this and I will tomorrow.

jfbu commented 2 years ago

aside: again I was not notified of issue creation; I am notified of comments on already created issues but not of issue creations... I saw this one yesterday because I came to the web interface

Yesterday was too tired and did not read your post carefully after this paragraph:

The situation is different (and far more complicated) for bp and mm though. I started by looking at inputs in mm unit, so X=floor(a*7227/2540) for some a=2540*k+r (r=0..2539). Since the behavior of X is periodic (mod 2540), we can focus on a=0..2539 only. Now the question is whether this X is attainable from bp or not.

You are right but expressed yourself at a too high level for a dummy like myself. For some reason, when I read that first I had not noticed that 7227=9*803. We want X = floor(a*7227/2540) to be also floor(b*803/800), i.e. X=floor(b*7227/7200). Out the 7227 congruence classes of X modulo 7227 this excludes 27 of them, which as stated in your post are those 27 which modulo 803 are in {267,535,802}. Now the first formula authorizes only 2540, i.e. about one third of all possible classes modulo 7227, and we are axcluding now 27 in total so we expect about 9 will have to be excluded from the 2540 possible values of floor(a*7227/2540). This you obtained by brute force, examining, actually, each of the three exclusion condition modulo 803 one at a turn.

So I agree with your analysis, but it looks a priori an overhead to check for a modulo 2540 and exclude there 9 values. It looks simpler once we have both X and a to apply the test on X mod. 803 that it has to be distinct from {267,535,802}. If it is not distinct we replace a by a-1 and X by a new one which will be either X-2 or X-3.

For implementation I must think: we can go brute force with existing macros, i.e., use first \texdimenmmdown then check if the obtained distance dimension remain invariant under \texdimenbp, if yes we are done, if not we know we must decrease by 1 the a (which verifies a sp = D pt where D = \texdimenmmdown{input}, but we will have hijacked the latter macro which actually computes a first).

As per complete math analytically, we are in a situation where we allow now only 2540-9=2531 values of X modulo 7227. But a priori the allowed X will not be those of the shape floor(k 7227/2531)... I have not checked, I admit a priori I can not believe such a thing will work. And any formula of the type X = floor(k G) where G is a reduced fraction A/B > 1 allows to recover G if we know the values of X for k=0..(B-1) simply by counting them. Time to break out before I err with too approximative things.

jfbu commented 2 years ago
1. get `a`;

2. test if `a=94`, `282`, `1035`, `1223`, `1317`, `1411`, `1505`, `1693`, or `2446` (mod 2540).

3. if not, leave `a` as is.

4. if yes, `a := a-1`.

I am going probably to do the following:

  1. get a and X (from \texdimenmmdown innards)
  2. test if X=267, 535, 802 modulo 803, i.e. if X sp is attainable by bp [or replace do this by any competitor to check if X sp is attainable by bp, perhaps simply use texdimenbp innards)
  3. if not, leave a as is.
  4. if yes a := a-1.

This scheme would be for a \texdimenbothbpmm whose output will be for mm. It seems for output in bp we need to add a fifth step which is

  1. ... and get the new X then obtain the result in bp unit from \texdimenbp or its innards.
jfbu commented 2 years ago

This was closed in 7795ab0e586a278519dcb4ef38f6960231fffeeb (#11)