summaryrefslogtreecommitdiff
path: root/macros/generic/texdimens/texdimens.tex
blob: c3aa10fc73bd5dd60d6a6cc89b3489e15b204cbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
% This is file texdimens.tex, part of texdimens package, which
% is distributed under the LPPL 1.3c. Copyright (c) 2021 Jean-François Burnol
% 2021/11/17 v1.1
\edef\texdimensendinput{\endlinechar\the\endlinechar%
\catcode`\noexpand _=\the\catcode`\_%
\catcode`\noexpand @=\the\catcode`\@\relax\noexpand\endinput}%
\endlinechar13\relax%
% only for using \p@ (also \z@ now) of Plain. Check if \p@, \z@ exists?
\catcode`\_=11 \catcode`\@=11
% so tempted to do \input xintkernel.sty to have some utilities...
% not even a \@gobble in Plain...
\def\texdimenfirstofone#1{#1}%
\def\texdimengobtilminus#1-{}%
\def\texdimenzerominusfork #10-#2#3\krof {#2}%
%
% \texdimenuu, \texdimenuudown, \texdimenuuup
% ===========================================
%
% Mathematics
% -----------
%
% In the entire discussion here, "uu" stands for some core unit,
% or some unit corresponding to an internal dimension > 1pt.
%
% Main question at the origin of this file was:
%     Is T sp attainable from unit "uu"?.
%     If not, what is largest dimension < Tsp which is?
%
% Here we suppose T>0. TeX parsing of D uu is equivalent to:
%
% D uu --> N = round(D * 65536) --> T = trunc (N * phi)
%
% phi>1 is the conversion factor associated to "uu"
% psi=1/phi, psi<1. Define U(N, phi) = trunc (N * phi)
%
%     U(N,phi) is thus the strictly increasing sequence,
%     indexed by non-negative integers, of non-negative
%     attainable dimensions. (in sp unit)
%
% T>0, then:
%
%     U(N)<= T <  U(N+1)    iff    N = ceil((T+1)psi) - 1
%     U(M)<  T <= U(M+1)    iff    M = ceil(T psi)    - 1
%
% In other words:
%
% - the largest attainable dimension not exceeding T sp
%   is obtained via the integer "Zd = ceil((T+1)psi) - 1 = N",
%   (i.e. find D with Zd=round(65536 D) then "D uu" is "down"
%    approximation)
%
% - the smallest attainable dimension at least equal to T sp
%   is obtained from the integer "Zu = ceil(T psi) = M + 1"
%
% - the two "Z"'s are either equal (i.e. T is attained) or Zu=Zd+1.
%
% \texdimenUU macros use round((T+0.5)*psi)
% -----------------------------------------
%
% case1:  M = N, i.e. Zd<Zu, i.e. T is not attainable:
%         M=N=Zd < T psi < (T+1) psi <= N+1=Zu
%
%         Then clearly R = round((T+0.5)psi) is either Zd or Zu.
%         We will not know which one before computing trunc(R phi)
%         and check if it is < T or > T.
%
%         As will be explained later trunc(R phi) can be computed very
%         easily by hijacking TeX's handling of dimensions, no \numexpr
%         chains is needed.
%
% case2:  M = N - 1, i.e. T = Zd = Zu is attained:
%         T psi <= N < (T+1) psi, T = trunc(N phi)
%
%         Let v=(T+0.5)psi. As v = T psi + 0.5 psi it is < N+0.5
%         And as v = (T+1)psi - 0.5psi it is > N - 0.5.
%         So R = round(v) = N.
%
% We thus have the initial observation which was at the core of this
% package initial release:
%
% - compute R = round((T+0.5) psi)
%
%   - if T is attained, then T = trunc(R * phi)
%
%   - if T is not attained then either { Zd = R and Zu = R+1 }  or
%     {Zd = R-1 and Zu = R}.
%
% How do we check if R = Zd or Zu? We need to evaluate trunc(R phi) and
% compare it with T. This trunc(R phi) can be computed the following way:
%
% - obtain D pt from \the\dimexpr R sp. Knuth's algorithm guarantees
%   that R = round(D * 65536)
%
% - then D uu where uu is the unit with conversion factor phi is
%   converted by TeX into "trunc(R phi) sp", i.e.  trunc(R phi) =
%   \number\dimexpr Duu\relax, where D pt = \the\dimexpr Rsp\relax.
%
% Conclusion:
%
% 1. the macro \texdimenuu does the one-liner R=round((T+0.5) psi)
%    then \the\dimexpr Rsp\relax gives "Dpt", the "pt" is removed,
%    we have a decimal D such that "Duu" does what one wants.
%
% 2. to get Zd (resp. Zu) one can use the D obtained in 1. and check
%    if "D uu" is at most (or at least) the user input dimension.
%
% For units with conversion factor phi>2, a simplification is possible.
% In that case let X = round(T psi) (it has the advantage compared to
% R that we can apply the formula without checking the sign of T).
%
% Going back to our earlier analyis, now with psi < 0.5 (1uu>2pt)
%
% case1: T is not attainable
%        M=N=Zd < T psi < (T+1) psi <= N+1=Zu
%        As Zd < T psi < Zu, we have round(T psi) = Zd or Zu
%
% case2: T is attained, i.e. T psi <= N < (T+1) psi.
%        As psi<0.5, and T psi + psi > N, we have T psi > N - 0.5.
%        And T psi <= N so N = round(T psi).
%
% So, for psi < 0.5, the X=round(T psi) can play the same role as
% R=round((T+0.5)psi). If T is attained, we get the decimal D from this
% X and if T is not attained we know that X is either Zd or Zu.
%
% The computations of X and Y=trunc(X phi) can be done independently of
% sign of T.  But the final test has to be changed to Y < T if T < 0 and
% then one must replace X by X+1. So we must filter out the sign of the
% input.
%
% Going back to the 1<phi<2 case, psi>0.5, then it would be slightly
% less costly to compute X = round(T psi) than R = round((T + 0.5) psi),
% but if we then realize that trunc(X phi) < T we do not yet know if
% trunc((X+1) phi) = T or is > T, i.e. we don't know if Zd =X or X+1,
% and we can not tell yet if T is attained or not.
%
% In contrast if we find out that trunc(R phi)<T, we then know for sure
% that Zd=R, Zu=R+1 and that T is not attained.
%
% Problems with \maxdimen in the obtention of Zu and Zd
% -----------------------------------------------------
%
% Obtaining R = round((T+0.5)psi) has no risk of overflow.
% But checking as described above which one of Zd or Zu (or both)
% is R goes via a test computation which will cause overflow
% if by bad luck R = Zu and Zu will give rise to a decimal D
% such that D uu > \maxdimen.
%
% For T=\maxdimen (or very close) this is what happens for the units
% "dd", "nc", and "in".
%
% Besides, it turns out that this test which is done to decide whether
% R=Zu or R=Zd, and on which the initial implementation of the macros
% "up" and "down" was done at 0.9 gamma release is a bit costly.
%
% At 1.0 release, all the "up" and "down" macros were re-implemented
% via a more stubborn usage of the ceil() based formulae for Zd and Zu.
% This made all usable even with \maxdimen input and besided, proved
% on average slightly faster.
%
% Overcoming the ceil() stumbling block for \texdimenUU{up,down}
% --------------------------------------------------------------
%
% I will in what follows refer to trunc(), floor() or ceil() only for
% positive arguments, obtained as ratios x/y or sometimes as a numexpr
% "scaling" operation" x*y/z which uses temporarily use doubled
% precision.
%
% As \numexpr's x/y is round(x/y), with rounding away from zero, we have
% access to floor(t) for t>=0 as round(t+0.5)-1 and for t>0 also as
% round(t-0.5). The former may cause overflow as it involves
% (2x+y)/(2y) but the latter (2x-y)/(2y) will not overflow if x comes
% from a dimension as 2x<2**31 then.
%
% ceil(t) is more complex as it is floor(t)+1 only for t not an integer.
% Let's explain how to overcome the challenge for Zd and the "in" unit,
% i.e. a conversion factor of 7227/100.
%
% We want Zd = ceil((T+1)*100/7227) - 1, with T assumed positive.
%
% Let T = k*7227 + r with 0<= r < 7227, 0<=k, and r>0 if k=0.
%
% (T+1)*100/7227 becomes 100*k + (r+1)*100/7227 and thus
%
% Zd = 100 * k + ceil(x) - 1
%
% with  x = n*100/7227, and n = 1+r, so 0<n<=7227
%
% Here we have a nice situation 0 < x <= 100. Then:
%
% ceil(x) = 100 - floor(100 - x)
%         = 100 - (round(100 - x + 0.5) - 1)
%         = 101 - round(100 * (1 - n/7227) + 0.5)
%         = 101 - round((200 * (7227 - n) + 7227)/14454)
%
% We can thus achieve the computation of Zd = ceil((T+1)*100/7227) - 1
% for T>0 without overflow in \numexpr this way:
%
%     k = floor(T/7227) = round(T/7227 - 0.5)
%                       = round((2*T - 7227) / 14454)  (T>0 used here)
%
%     r = T - 7227 * k  = T modulo 7227
%
%     Zd = 100 * k + 100 - round( (201*7227 - 200*(r+1))/14454 )
%
% Everything here is computable within \numexpr and has absolutely no
% potential overflow problem at all. The same analysis can be done for
% Zu = ceil(T*100/7227) and for all core TeX units. See the comments
% below for all obtained formulae and some additional details.
%
{\catcode`p 12\catcode`t 12
 \csname expandafter\endcsname\gdef\csname texdimenstrippt\endcsname#1pt{#1}}%
%
% pt
%
\def\texdimenpt#1{\expandafter\texdimenstrippt\the\dimexpr#1\relax}%
%
% bp 7227/7200 = 803/800
%
\def\texdimenbp#1{\expandafter\texdimenstrippt\the\dimexpr\numexpr(%
                  \expandafter\texdimen_bpnddd_signcheck
                  \the\numexpr2*\dimexpr#1\relax\relax)*400/803sp\relax}%
\def\texdimen_bpnddd_signcheck#1{\texdimengobtilminus#1-1+#1}%
%
% nd 685/642
%
\def\texdimennd#1{\expandafter\texdimenstrippt\the\dimexpr\numexpr(%
                  \expandafter\texdimen_bpnddd_signcheck
                  \the\numexpr2*\dimexpr#1\relax\relax)*321/685sp\relax}%
%
% dd 1238/1157
%
\def\texdimendd#1{\expandafter\texdimenstrippt\the\dimexpr\numexpr(%
                  \expandafter\texdimen_bpnddd_signcheck
                  \the\numexpr2*\dimexpr#1\relax\relax)*1157/2476sp\relax}%
%
% mm 7227/2540 phi now >2, use from here on the X = round(T psi) approach
%
\def\texdimenmm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*2540/7227\relax}%
%
% pc 12/1
%
\def\texdimenpc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)/12\relax}%
%
% nc 1370/107
%
\def\texdimennc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*107/1370\relax}%
%
% cc 14856/1157
%
\def\texdimencc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*1157/14856\relax}%
%
% cm 7227/254
%
\def\texdimencm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*254/7227\relax}%
%
% in 7227/100
%
\def\texdimenin#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*100/7227\relax}%
%
% "up and down macros"
% --------------------
%
% The notation <u/v> means u/v in numexpr, which does rounding
% away from zero. It is essential that the argument be >-0.5 else <x+1>
% not same as <x>+1. All formulae are overflow free.
%
% The comments are for T > 0.
%
% Roughly such an approach works for phi = a/b > 1, such that:
%
%     a*(2b+1)<2**31 if a is odd, <2**32 if a is even
%
% This is true for all core units with quite some margin, the one with
% largest a*b being phi=7227/2540 for "mm".
%
% Note: for a unit such as "ex" or "em" where morally b=65536=2**16,
% this limits to a<=16383 if a is odd and to a<=32766 if a is even.
% Thus the general \texdimenwithunit{dim1}{dim2} (which for dim2<1pt
% computes basically an "up" value) can *not imitate fully* this scheme.
%
% The macros and formulas in the comments were obtained from a template
% (see file generateupdownmacros.py at the project repository),
% and we could actually combine them into a generic macro handling
% general a/b (assuming above bounds are verified).
% But for the the sake of efficiency, this is "rolled-out" here unit per unit.
%
\def\texdimenuudownup_zero#1;{\z@\relax}%
\def\texdimenuudownup_neg#1-{-#1}%
% bp 803/800
% T = 803 k + r
% Zd = 800 k + 800 - <(1284003 - 1600 r)/1606>
\def\texdimenbpdown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenbpdown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenbpdown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimenbpdown_b#1}%
\def\texdimenbpdown_b#1;{\expandafter\texdimenbpdown_c\the\numexpr(2*#1-803)/1606;#1;}%
\def\texdimenbpdown_c#1;#2;{\expandafter\texdimenbpdown_d\the\numexpr#2-803*#1;#1;}%
\def\texdimenbpdown_d#1;#2;{\numexpr800*#2+800-(1284003-1600*#1)/1606sp\relax}%
% Zu = 800 k + 800 + 1 - <(1285603 - 1600 r)/1606>
\def\texdimenbpup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenbpup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenbpup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimenbpup_b#1}%
\def\texdimenbpup_b#1;{\expandafter\texdimenbpup_c\the\numexpr(2*#1-803)/1606;#1;}%
\def\texdimenbpup_c#1;#2;{\expandafter\texdimenbpup_d\the\numexpr#2-803*#1;#1;}%
\def\texdimenbpup_d#1;#2;{\numexpr800*#2+801-(1285603-1600*#1)/1606sp\relax}%
% nd 685/642
% T = 685 k + r
% Zd = 642 k + 642 - <(878941 - 1284 r)/1370>
\def\texdimennddown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimennddown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimennddown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimennddown_b#1}%
\def\texdimennddown_b#1;{\expandafter\texdimennddown_c\the\numexpr(2*#1-685)/1370;#1;}%
\def\texdimennddown_c#1;#2;{\expandafter\texdimennddown_d\the\numexpr#2-685*#1;#1;}%
\def\texdimennddown_d#1;#2;{\numexpr642*#2+642-(878941-1284*#1)/1370sp\relax}%
% Zu = 642 k + 642 + 1 - <(880225 - 1284 r)/1370>
\def\texdimenndup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenndup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenndup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimenndup_b#1}%
\def\texdimenndup_b#1;{\expandafter\texdimenndup_c\the\numexpr(2*#1-685)/1370;#1;}%
\def\texdimenndup_c#1;#2;{\expandafter\texdimenndup_d\the\numexpr#2-685*#1;#1;}%
\def\texdimenndup_d#1;#2;{\numexpr642*#2+643-(880225-1284*#1)/1370sp\relax}%
% dd 1238/1157
% T = 1238 k + r
% Zd = 1157 k + 1157 - <(1431828 - 1157 r)/1238>
\def\texdimendddown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimendddown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimendddown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimendddown_b#1}%
\def\texdimendddown_b#1;{\expandafter\texdimendddown_c\the\numexpr(#1-619)/1238;#1;}%
\def\texdimendddown_c#1;#2;{\expandafter\texdimendddown_d\the\numexpr#2-1238*#1;#1;}%
\def\texdimendddown_d#1;#2;{\numexpr1157*#2+1157-(1431828-1157*#1)/1238sp\relax}%
% Zu = 1157 k + 1157 + 1 - <(1432985 - 1157 r)/1238>
\def\texdimenddup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenddup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenddup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimenddup_b#1}%
\def\texdimenddup_b#1;{\expandafter\texdimenddup_c\the\numexpr(#1-619)/1238;#1;}%
\def\texdimenddup_c#1;#2;{\expandafter\texdimenddup_d\the\numexpr#2-1238*#1;#1;}%
\def\texdimenddup_d#1;#2;{\numexpr1157*#2+1158-(1432985-1157*#1)/1238sp\relax}%
% mm 7227/2540
% T = 7227 k + r
% Zd = 2540 k + 2540 - <(36715307 - 5080 r)/14454>
\def\texdimenmmdown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenmmdown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenmmdown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimenmmdown_b#1}%
\def\texdimenmmdown_b#1;{\expandafter\texdimenmmdown_c\the\numexpr(2*#1-7227)/14454;#1;}%
\def\texdimenmmdown_c#1;#2;{\expandafter\texdimenmmdown_d\the\numexpr#2-7227*#1;#1;}%
\def\texdimenmmdown_d#1;#2;{\numexpr2540*#2+2540-(36715307-5080*#1)/14454sp\relax}%
% Zu = 2540 k + 2540 + 1 - <(36720387 - 5080 r)/14454>
\def\texdimenmmup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenmmup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenmmup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimenmmup_b#1}%
\def\texdimenmmup_b#1;{\expandafter\texdimenmmup_c\the\numexpr(2*#1-7227)/14454;#1;}%
\def\texdimenmmup_c#1;#2;{\expandafter\texdimenmmup_d\the\numexpr#2-7227*#1;#1;}%
\def\texdimenmmup_d#1;#2;{\numexpr2540*#2+2541-(36720387-5080*#1)/14454sp\relax}%
% pc 12/1
% T = 12 k + r
% Zd = 1 k + 1 - <(17 - 1 r)/12>
\def\texdimenpcdown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenpcdown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenpcdown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimenpcdown_b#1}%
\def\texdimenpcdown_b#1;{\expandafter\texdimenpcdown_c\the\numexpr(#1-6)/12;#1;}%
\def\texdimenpcdown_c#1;#2;{\expandafter\texdimenpcdown_d\the\numexpr#2-12*#1;#1;}%
\def\texdimenpcdown_d#1;#2;{\numexpr#2+1-(17-#1)/12sp\relax}%
% Zu = 1 k + 1 + 1 - <(18 - 1 r)/12>
\def\texdimenpcup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenpcup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenpcup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimenpcup_b#1}%
\def\texdimenpcup_b#1;{\expandafter\texdimenpcup_c\the\numexpr(#1-6)/12;#1;}%
\def\texdimenpcup_c#1;#2;{\expandafter\texdimenpcup_d\the\numexpr#2-12*#1;#1;}%
\def\texdimenpcup_d#1;#2;{\numexpr#2+2-(18-#1)/12sp\relax}%
% nc 1370/107
% T = 1370 k + r
% Zd = 107 k + 107 - <(147168 - 107 r)/1370>
\def\texdimenncdown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenncdown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenncdown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimenncdown_b#1}%
\def\texdimenncdown_b#1;{\expandafter\texdimenncdown_c\the\numexpr(#1-685)/1370;#1;}%
\def\texdimenncdown_c#1;#2;{\expandafter\texdimenncdown_d\the\numexpr#2-1370*#1;#1;}%
\def\texdimenncdown_d#1;#2;{\numexpr107*#2+107-(147168-107*#1)/1370sp\relax}%
% Zu = 107 k + 107 + 1 - <(147275 - 107 r)/1370>
\def\texdimenncup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenncup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenncup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimenncup_b#1}%
\def\texdimenncup_b#1;{\expandafter\texdimenncup_c\the\numexpr(#1-685)/1370;#1;}%
\def\texdimenncup_c#1;#2;{\expandafter\texdimenncup_d\the\numexpr#2-1370*#1;#1;}%
\def\texdimenncup_d#1;#2;{\numexpr107*#2+108-(147275-107*#1)/1370sp\relax}%
% cc 14856/1157
% T = 14856 k + r
% Zd = 1157 k + 1157 - <(17194663 - 1157 r)/14856>
\def\texdimenccdown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenccdown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenccdown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimenccdown_b#1}%
\def\texdimenccdown_b#1;{\expandafter\texdimenccdown_c\the\numexpr(#1-7428)/14856;#1;}%
\def\texdimenccdown_c#1;#2;{\expandafter\texdimenccdown_d\the\numexpr#2-14856*#1;#1;}%
\def\texdimenccdown_d#1;#2;{\numexpr1157*#2+1157-(17194663-1157*#1)/14856sp\relax}%
% Zu = 1157 k + 1157 + 1 - <(17195820 - 1157 r)/14856>
\def\texdimenccup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenccup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenccup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimenccup_b#1}%
\def\texdimenccup_b#1;{\expandafter\texdimenccup_c\the\numexpr(#1-7428)/14856;#1;}%
\def\texdimenccup_c#1;#2;{\expandafter\texdimenccup_d\the\numexpr#2-14856*#1;#1;}%
\def\texdimenccup_d#1;#2;{\numexpr1157*#2+1158-(17195820-1157*#1)/14856sp\relax}%
% cm 7227/254
% T = 7227 k + r
% Zd = 254 k + 254 - <(3678035 - 508 r)/14454>
\def\texdimencmdown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimencmdown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimencmdown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimencmdown_b#1}%
\def\texdimencmdown_b#1;{\expandafter\texdimencmdown_c\the\numexpr(2*#1-7227)/14454;#1;}%
\def\texdimencmdown_c#1;#2;{\expandafter\texdimencmdown_d\the\numexpr#2-7227*#1;#1;}%
\def\texdimencmdown_d#1;#2;{\numexpr254*#2+254-(3678035-508*#1)/14454sp\relax}%
% Zu = 254 k + 254 + 1 - <(3678543 - 508 r)/14454>
\def\texdimencmup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimencmup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimencmup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimencmup_b#1}%
\def\texdimencmup_b#1;{\expandafter\texdimencmup_c\the\numexpr(2*#1-7227)/14454;#1;}%
\def\texdimencmup_c#1;#2;{\expandafter\texdimencmup_d\the\numexpr#2-7227*#1;#1;}%
\def\texdimencmup_d#1;#2;{\numexpr254*#2+255-(3678543-508*#1)/14454sp\relax}%
% in 7227/100
% T = 7227 k + r
% Zd = 100 k + 100 - <(1452427 - 200 r)/14454>
\def\texdimenindown#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenindown_a\the\numexpr\dimexpr#1;%
}%
\def\texdimenindown_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                        \krof \texdimenindown_b#1}%
\def\texdimenindown_b#1;{\expandafter\texdimenindown_c\the\numexpr(2*#1-7227)/14454;#1;}%
\def\texdimenindown_c#1;#2;{\expandafter\texdimenindown_d\the\numexpr#2-7227*#1;#1;}%
\def\texdimenindown_d#1;#2;{\numexpr#200+100-(1452427-2*#100)/14454sp\relax}%
% Zu = 100 k + 100 + 1 - <(1452627 - 200 r)/14454>
\def\texdimeninup#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimeninup_a\the\numexpr\dimexpr#1;%
}%
\def\texdimeninup_a#1{\texdimenzerominusfork
                        #1-\texdimenuudownup_zero
                        0#1\texdimenuudownup_neg
                         0-{}%
                      \krof \texdimeninup_b#1}%
\def\texdimeninup_b#1;{\expandafter\texdimeninup_c\the\numexpr(2*#1-7227)/14454;#1;}%
\def\texdimeninup_c#1;#2;{\expandafter\texdimeninup_d\the\numexpr#2-7227*#1;#1;}%
\def\texdimeninup_d#1;#2;{\numexpr#200+101-(1452627-2*#100)/14454sp\relax}%
%
% "both in and cm"
% ================
%
% Mathematics
% -----------
%
% Let a and b be two non-negative integers such that U = floor(a 7227/100) = 
% floor(b 7227/254).  It can be proven that a=50k, b=127k for some integer k.
% The proof is left to reader.  So U = floor(7227 k /2) for some k.
%
% Let's now find the largest such U <= T. So U = floor(k 7227/2)<= T which is
% equivalent (as k is integer) to k 7227/2 <= T + 1/2, i.e.
%
%     kmax = floor((2T+1)/7227)
%
% If we used for x>0 the formula floor(x)=round(x-1/2)=<x-1/2> we would end
% up basically with some 4T hence overflow problems even in \numexpr.
% Here I used <.> to denote rounding in the sense of \numexpr. It is not
% 1-periodical due to how negative inputs are handled, but here x-1/2>-1/2.
%
% The following lemma holds: let T be a non-negative integer then
%
%     floor((2T+1)/7227) = <(2T - 3612)/7227>
%
% So we can compute this k, hence get a=50k, b=127k, all within \numexpr and
% avoiding overflow.
%
% Implementation
% --------------
%
% Regarding the output in pt or sp, we seem to need floor(k 7227/2).
% The computation of floor(k 7227/2) as <(7227 k - 1)/2> would require to
% check if k==0 so we do it rather as <(7227 k + 1)/2> - 1.  No overflow
% can arise as k = 297147 for \maxdimen, and then 7227 k = 2**31 - 2279 and
% there is ample room for 7227k+1 using \numexpr.
%
% But this step, as well as initial step to get kmax will require to separate
% handling of negative input from positive one.
%
% Alternative
% -----------
%
% For non-negative T we can compute U = ((T+1)/7227)*7227. If U <= T keep it,
% else if U > T, replace it by U - 3614. This is alternative road to the maximal
% floor(k 7227/2) at most equal to T.
%
\def\texdimenbothincm#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenboth_a
    \the\numexpr\dimexpr#1\relax\relax-3612)/7227)*127sp\relax}%
\def\texdimenbothcmin#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenboth_a
    \the\numexpr\dimexpr#1\relax\relax-3612)/7227)*50sp\relax}%
\def\texdimenboth_a#1{\texdimengobtilminus#1\texdimenboth_neg-\numexpr((2*#1}%
\def\texdimenboth_neg-\numexpr((2*-{-\numexpr((2*}%
%
\def\texdimenbothincmsp#1{\number
    \expandafter\texdimenbothsp_a\the\numexpr\dimexpr#1\relax\relax
     -3612)/7227)*7227+1)/2-1\relax}%
\def\texdimenbothincmpt#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenbothsp_a\the\numexpr\dimexpr#1\relax\relax
     -3612)/7227)*7227+1)/2-1sp\relax}%
\def\texdimenbothsp_a#1{\texdimengobtilminus#1\texdimenbothsp_neg-\numexpr(((2*#1}%
\def\texdimenbothsp_neg-\numexpr(((2*-{-\numexpr(((2*}%
%
\let\texdimenbothcminpt\texdimenbothincmpt
\let\texdimenbothcminsp\texdimenbothincmsp
%
% "both mm and bp"
% ================
%
% Mathematics and Algorithm
% -------------------------
%
% We start from a dimension expressed in sp unit, "T sp". Assume T positive.
% We know how to get largest "X sp <= T sp" which is exactly expressible
% in mm unit
% i.e. can be written X=trunc(a 7227/2540) for some non-negative integer a.
% We want to achieve X=trunc(b 803/800) for some b.
%
%    Only the congruence of X modulo 803 matters for this.
%    It turns out that the mod 803 impossible values are 267, 535, 802.
%    As pointed out by Ruixi Zhang on the package repo issue #10,
%    when a<--a+2540, X increases by 7227=9*803 hence the value
%    modulo 803 does not change. Thus only "a modulo 2540" matters
%    to check if X(a) is attainable with bp unit. Ruixi Zhang found by
%    brute force that there are modulo 2540 nine excluded a-values
%
% Rather than checking if "a mod. 2540" avoids the 9 Ruixi Zhang values
% or if "X mod. 803" avoids  267, 535, 802, we will simply basically
% check if X sp = \texdimenbp{X sp}bp, as this approach is probably
% about the same cost or even less than computing "X mod. 803" and
% correspondingly branching.
%
% The key is that if "a" is bad, then "a-1" is automatically good as
% pointed out by R.Z. on #10, which can be seen without knowing the 9
% bad congruences, simply by noticing that a<--a-1 modifies X either to
% X-2 or X-3, so if X was bad certainly the new one is not.
%
% Once "a" has gotten its final value, we apply "\the\dimexpr a sp
% = D pt" trick to recover the D such that "D mm" gives rise to the found
% dimension.  We go via this "Dmm" intermediary also to express the final
% result as "X sp", because anyhow the "X" we worked with and had in
% our token stream has to be recomputed if a<--a-1, so lets always
% recompute it from final "a", and this goes via "D mm" (but see
% the paragraph MEMO for alternative for this trunc(a 7227/2540) step).
%
% I will copy here the style I used for bothincm expansion triggering
% via an already positioned \dimexpr waiting to output final result.
\def\texdimenbothbpmm#1{\expandafter\texdimenstrippt\the\dimexpr
                        \expandafter\texdimenbothbpmm_fork\the\numexpr\dimexpr#1;}%
\def\texdimenbothbpmm_fork#1{\texdimenzerominusfork
                             #1-\texdimenbothbpmm_zero
                             0#1\texdimenbothbpmm_neg
                             0-\texdimenbothbpmm_a
                             \krof#1}%
% because this is *inside* a pre-positioned \dimexpr, we don't have
% to worry about zero output ending up as -0.0
\def\texdimenbothbpmm_neg-{-\texdimenbothbpmm_a}%
\def\texdimenbothbpmm_zero#1;{\z@\relax}%
% now, find X sp <= T sp maximal and expressible in mm unit
% it will be X=trunc(a 7227/2540), we first get a candidate for "a"
\def\texdimenbothbpmm_a#1;%
    {\expandafter\texdimenbothbpmm_b\the\numexpr#1*2540/7227;#1;}%
% we get in a single line the X from this candidate, hijacking TeX's
% built-in *7227/2540... the "MEMO" above explains one could do this
% purely within \numexpr, working around its division rounds, and
% avoiding overflow, but I suspect this would be more costly.
\def\texdimenbothbpmm_b#1;{\expandafter\texdimenbothbpmm_c
    \the\numexpr\dimexpr\expandafter\texdimenstrippt\the\dimexpr#1spmm;#1;}%
% now we have X;a;T;
\def\texdimenbothbpmm_c#1;#2;#3;{%
% If X>T, our candidate "a=#2" must be decreased by 1 and we go to _ca
% The original #3 is not needed anymore
    \ifnum#1>#3 \expandafter\texdimenbothbpmm_ca\fi
% Else we decide whether it is "a" or "a-1" we must use. I preferred
% to induce a re-grabbing cost here, rather than have \texdimenbothbpmm_ca
% re-grab its arguments from \texdimenbothbpmm_d replacement text.
    \texdimenbothbpmm_d#1;#2;%
}%
% Here, dynamically at the time of the concluding \dimexpr, we
% check if X sp is expressible in bp unit and then use "a" or "a-1"
% accordingly
\def\texdimenbothbpmm_d#1;#2;{#2sp%
    \ifnum\dimexpr
    \expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1+1)*400/803spbp=#1
    \else-1sp\fi
% and a \relax to stop the concluding \dimexpr
    \relax
}%
% Here we must decrease "a=#2" by 1, recompute X=#1, then loop
% back to \texdimenbothbpmm_d. Hesitation between forcing a
% re-grab or doing it in one step with the subtraction of 1 done twice
\def\texdimenbothbpmm_ca\texdimenbothbpmm_d#1;#2;%
   {\expandafter\texdimenbothbpmm_cb\the\numexpr#2-1;}%
\def\texdimenbothbpmm_cb#1;{%
    \expandafter\texdimenbothbpmm_d
    \the\numexpr\dimexpr\expandafter\texdimenstrippt\the\dimexpr#1spmm;#1;%
}%
% done...
% now the lazy way for \texdimenbothmmbp
\def\texdimenbothmmbp#1{\expandafter\texdimenstrippt\the\dimexpr
    \expandafter\texdimenbothmmbp_a\the\numexpr\dimexpr\texdimenbothbpmm{#1}mm;}%
% If zero at this stage, we will correctly get 0.0 in the end
\def\texdimenbothmmbp_a#1#2;{\numexpr(2*#1#2+\texdimengobtilminus#1-1)*400/803sp\relax}%
% \texdimenbothbpmmpt and its alias \texdimenbothmmbppt
\def\texdimenbothbpmmpt#1{\texdimenpt{\texdimenbothbpmm{#1}mm}}%
\let\texdimenbothmmbppt\texdimenbothbpmmpt
% \texdimenbothbpmmsp and its alias \texdimenbothmmbpsp
\def\texdimenbothbpmmsp#1{\the\numexpr\dimexpr\texdimenbothbpmm{#1}mm\relax\relax}%
\let\texdimenbothmmbpsp\texdimenbothbpmmsp
%
% \texdimenwithunit
% =================
%
% Mathematics
% -----------
%
% The ex and em units are handled by TeX as if multiplying by a
% conversion factor f/65536 (here f sp = 1ex resp. = 1em).
%
% In particular, for any decimal D, input "D em" is handled the exact
% same way as input "D\dimexpr 1em\relax"; this is not
% the case for the core units except for pt and pc (and sp), whose
% conversion factors are the sole ones with a power of 2 denominator
% (respectively 1, 1, and 65536).  The further difference is that
% for the core units apart from sp, the conversion factor is >1.
%
% We assume for this discussion T is non-negative.
% If f/65536 > 1, the analysis is as above : some dimensions T sp
% are not attainable as D uu, but the formula
%     N=round((2T+1)*32768/f)
% will give a suitable decimal D via \the\dimexpr N sp\relax.
% (if T=0, we get N=0 as 32768/f<0.5)
% This D will let TeX convert D uu into T sp, if the dimension
% is attainable else it will be a closest match
% either from above or below (not necessarily nearest overall).
%
% If f/65536=1, attention that above formula would give N=1 for
% T=0 (was bug #4).
%
% If f/65536<1, all dimensions Tsp are attainable as D uu. Indeed
% D uu is parsed by TeX via N=round(D*65536), then T=trunc(N*phi),
% with phi=f/65536. Starting from T we need to find an N such that
% T/phi <= N< (T+1)/phi.
%
% This is equivalent to ceil(T/phi)<= N < ceil((T+1)/phi)
%
% Now obsolete remark: let v=(T+0.5)/phi. As its
% distance to the extremities is 0.5/phi>0.5, (phi>1) its rounding M
% to an integer verifies automatically T/phi < M < (T+1)/phi, so
% is a valid candidate. This was used at 0.99 release.
% (it is funny that N=round((2T+1)*32768/f) works for all f>0
%  *except* f=65536).
%
% The 1.0 release chooses to implement the ceil(T/phi) formula rather as
% it is closer to naive expectation "dim1/dim2" of a division.
%
% It is not obvious to compute this ceil(T/phi) without overflow.
%
% Implementation
% --------------
%
% \texdimenwithunit{dim1}{dim2}
%
% First done at 0.99, then refactored at 1.0:
% - to add support for dim2<0pt
% - to handle differently the dim2<1pt case and make the output
%   closer to mathematical dim1/dim2
%
% To handle dim2<0pt, we simply simultaneously do
% dim1<-- (-dim1) and dim2<-- (-dim2).
%
% dim2=0pt is not intercepted and will cause division by zero low-level
% error.  Code comments below were not adjusted and handle only
% dim2>0pt.
%
% We first get f from dim2 and branch according to whether f>65536,
% or f<=65536.
% We will also need to check the sign of T (dim1=T sp).
% f>65536: we compute round((2T+1)*32768/f)
% f=65536: merged with f<65536 branch (as it works and avoids checking for it)
% f<65536: 0.99 release used the round((2T+1)*32768/f) formula
%          (it is funny that it works for all f except for f=65536)
%
%          But the output then diverges noticeably from mathematical
%          dim1/dim2 "=" T*65536/f, the more so the smaller the dim2.
%          See issue #16 and also the discussion at #13.
%
%          1.0 release thus opted for the ceil(T*65536/f) formula, as it is the
%          smallest allowable choice, hence the closest to naive dim1/dim2.
%
%          To avoid arithmetic overflow issues we first do the euclidean
%          division T = k f + r, 0<= r < f, 0<= k
%
%          The final result in "sp" unit would be k*65536 + C with
%          C = ceil(r * 65536/f).
%
%          We don't do this k*65536 explicitly as it may overflow and is
%          anyhow unneeded: the output will be the integer k concatenated with
%          the decimal E given by TeX from \the\dimexpr C sp, i.e. such that
%          E pt = C sp, with C = ceil(r*65536/f).
%
%          As r is at most f-1, r*65536/f is at most 65536-65536/f, and as
%          65536>=f (we use this branch also for f=65536), C<=65535. Hence
%          E is never 1.0 but always "0.<some digits>"
%
%          To compute the Euclidean quotient k in \numexpr we use there
%          <(2T-f)/(2f)> i.e. round((2T-f)/2f) = trunc(T/f)
%          as we are careful to never have T=0 in-there...
%
%          Computing C = ceil(r * 65536/f) in \numexpr is the delicate
%          part, as r can be as large as f-1 hence 65535 and 65535*65536 would
%          overflow.  Let's try anyhow to see how to compute ceil() with round():
%
%          C = 65536 - floor(65536 * (1 - r/f))
%            = 65536 - round(65536*(f-r)/f - 0.5) (as r<f so no "round(-0.5)=-1")
%            = 65536 - <(2*65536*(f-r) - f)/(2f)>
%
%          Here the problem is with small r, and large f, and naive implementation
%          of this formula can overflow...
%          Let's thus retreat to eTeX scaling operation <r*65536/f> as it
%          operates with temporary double precision.
%
%          R=round(r*65536/f)=<r*65536/f> is either C-1 or C
%          Let x = mathematical exact r*65536/f:
%          - if R < x,  C=R+1.
%          - if R >= x, C=R.
%
%          C=ceil(r*65536/f) is the smallest integer such that
%          trunc(C*f/65536)>=r, or more precisely (as f<=65536) the
%          smallest integer with trunc(C*f/65536)=r. So trunc(R*f/65536)
%          will be either r (then R=C), or r-1, then R=C-1.
%
%          Method from release 1.0: let's TeX compute P=trunc(R*f/65536) itself!
%          Via P sp = E <f sp> where E is a decimal such that E pt = R sp.
%          So
%          - if P>=r (it is then equal to r in fact) then C=R
%          - if P<r (it is then equal to r-1), then C=R+1.
%
%          New method: overflow-free pure \numexpr way to get the sign of R-x.
%
%          Write R=4*S+t, with say S=<R/4>=round(R/4), so t=-2,-1,0,+1.
%
%          Then R*f-65536*r = 4*(S*f-16384*r)+t*f
%
%          We know that R<=C<65536, so <R/4> <= 16384 and 16384*f
%          is at worst 2**(14+16)=\maxdimen+1 but we will be in \numexpr,
%          so no overflow!
%          And r<f<=65536 so also 16384*r can not overflow.
%          As |R - r*65536/f|<= 0.5, then |R*f-65536*r|<= f/2, so
%          4*|S*f-16384*r| <= 2.5*f is very far from overflow risk
%
%              T>0, 0<f<=65536
%              k = <(2*T-f)/(2*f)>
%              r = T - k*f
%              R=<r*65536/f>
%              S=<R/4>
%              t=R-4*S
%
%              IF: 4*(S*f-16384*r)+t*f < 0 THEN C=R+1 ELSE C=R.
%
%              Ept=\the\dimexpr Csp, E=0.d...d
%
%              End expansion with the contatenation k.d...d
%
\def\texdimenwithunit#1#2{\expandafter\texdimenwithunit_i
% no premultiplication of dim1 by 2 as was done for technical
% reasons when dim2<1pt branch used round((2T+1)*32768/f)
    \the\numexpr\dimexpr#2\expandafter;\the\numexpr\dimexpr#1;%
}%
\def\texdimenwithunit_i#1{%
     \texdimengobtilminus#1\texdimenwithunit_switchsigns-%
     \texdimenwithunit_j#1%
}%
\def\texdimenwithunit_switchsigns-\texdimenwithunit_j-#1;#2%
{%
% due to \texdimenwithunit_Bneg we can not simply prefix dim1
% with -, as -0 is bad there. So let's check also if #2 is 0
    \texdimenzerominusfork
      #2-\texdimenwithunit_Bzero % also used in \texdimenwithunit_B
      0#2\texdimenwithunit_j     % abusive shortcut
       0-{\texdimenwithunit_ic#2}%
    \krof
    #1;%
}%
\def\texdimenwithunit_ic#1#2;{\texdimenwithunit_j#2;-#1}%
\def\texdimenwithunit_j#1;#2{%
        \ifnum#1>\p@\texdimenwithunit_A\fi
        \texdimenwithunit_B#2#1;%
}%
% unit>1pt, handle this as for bp.
% Attention it would be wrong for unit=1pt!
\def\texdimenwithunit_A\fi\texdimenwithunit_B#1#2;#3;{\fi
    \expandafter\texdimenstrippt
    \the\dimexpr\numexpr(2*#1#3+\texdimengobtilminus#1-1)*32768/#2sp\relax
    % - fine if dim1>0, <0, or =0
    % - with *\p@ better but an early doubled dim2 would complicate 1pt
    % test and not sure if doing \p@/(2*#2) here advantageous
}%
% unit<=1pt.
% if dim1<0, simply negate result for dim1>0 as it can not possibly be 0.0
% Indeed T*65536/f will be at least 1 so its ceil also (in fact ceil
% will even be at least 2 if f<65536).
% The dim1=0 case must get filtered out due to way of calculating the
% "ceil" in \numexpr
\def\texdimenwithunit_B#1{\texdimenzerominusfork
                           #1-\texdimenwithunit_Bzero
                           0#1\texdimenwithunit_Bneg
                            0-\texdimenwithunit_Ba
                          \krof#1}%
\def\texdimenwithunit_Bzero#1;#2;{0.0}%
\def\texdimenwithunit_Ba#1#2;#3;{%
    % no overflow possible from 2*#1#3 in \numexpr
    \expanded{\expandafter\texdimenwithunit_Bb
              \the\numexpr(2*#1#3-#2)/(2*#2);#1#3;#2;}%
}%
% I could have inserted \expanded\bgroup in \texdimenwithunit_B
% but then needed to modify _Bzero (used also by \texdimenwithunit_switchsigns)
% so easiest is to simply defined Bneg explicitly here rather than
% insisting on deriving it from _Ba
\def\texdimenwithunit_Bneg-#1;#2;{%
    \expanded{-\expandafter\texdimenwithunit_Bb
               \the\numexpr(2*#2-#1)/(2*#1);#2;#1;}%
}%
% now k;T;f;. Get the remainder r=T-k*f, and abandon k in the token stream.
% the earlier \expanded maintains f-expandability
\def\texdimenwithunit_Bb#1;#2;#3;{%
    #1\expandafter\texdimenwithunit_Bc\the\numexpr#2-#1*#3;#3;%
}%
% now r;f;. Get R=<r*65536/f>
\def\texdimenwithunit_Bc#1;#2;{%
    \expandafter\texdimenwithunit_Bd\the\numexpr #1*\p@/#2;#1;#2;%
}%
% R;r;f; Is 4*(S*f-16384*r)+t*f < 0 ? with S=<R/4>, t=R-4S
\def\texdimenwithunit_Bd#1;#2;#3;{%
    \expandafter\texdimenwithunitstripzeroandpt
    \the\dimexpr\numexpr#1%
    \ifnum\numexpr 4*((#1/4)*#3-16384*#2)<\numexpr(4*(#1/4)-#1)*#3\relax
     +1\fi sp\relax
}%
{\catcode`P12\catcode`T12\lowercase{\gdef\texdimenwithunitstripzeroandpt0#1PT}{#1}}%
\texdimensendinput