@@ -1269,6 +1269,151 @@ public void Issue91ToFloatString()
1269
1269
}
1270
1270
}
1271
1271
1272
+ [ Test ]
1273
+ public void TestShortenMantissaBigDelta ( )
1274
+ {
1275
+ Assert . AreEqual ( Decimal64 . Parse ( "9000000000000000" ) ,
1276
+ Decimal64 . Parse ( "9999000000000000" ) . ShortenMantissa ( DotNetImpl . MaxCoefficient / 2 , 2 ) ) ;
1277
+ }
1278
+
1279
+ [ Test ]
1280
+ public void TestShortenMantissaCase006 ( )
1281
+ {
1282
+ String testString = "0.006" ;
1283
+ var testValue = Double . Parse ( testString ) ;
1284
+ var testX = 0.005999999999998265 ; // Math.nextDown(testValue);
1285
+
1286
+ var d64 = Decimal64 . FromDouble ( testX ) . ShortenMantissa ( 1735 , 1 ) ;
1287
+ Assert . AreEqual ( testString , d64 . ToString ( ) ) ;
1288
+
1289
+ Decimal64 . FromDouble ( 9.060176071990028E-7 ) . ShortenMantissa ( 2 , 1 ) ;
1290
+ }
1291
+
1292
+ [ Test ]
1293
+ public void TestShortenMantissaRandom ( )
1294
+ {
1295
+ var randomSeed = new Random ( ) . Next ( ) ;
1296
+ var random = new Random ( randomSeed ) ;
1297
+
1298
+ try
1299
+ {
1300
+ for ( int iteration = 0 ; iteration < N ; ++ iteration )
1301
+ {
1302
+ var mantissa = GenerateMantissa ( random , Decimal64 . MaxSignificandDigits ) ;
1303
+ int error = random . Next ( 3 ) - 1 ;
1304
+ mantissa = Math . Min ( DotNetImpl . MaxCoefficient , Math . Max ( 0 , ( ulong ) ( ( long ) mantissa + error ) ) ) ;
1305
+ if ( mantissa <= DotNetImpl . MaxCoefficient / 10 )
1306
+ mantissa = mantissa * 10 ;
1307
+
1308
+ var delta = GenerateMantissa ( random , 0 ) ;
1309
+ if ( delta > DotNetImpl . MaxCoefficient / 10 )
1310
+ delta = delta / 10 ;
1311
+
1312
+ CheckShortenMantissaCase ( mantissa , delta ) ;
1313
+ }
1314
+ }
1315
+ catch ( Exception e )
1316
+ {
1317
+ throw new Exception ( "Random seed " + randomSeed + " exception: " + e . Message , e ) ;
1318
+ }
1319
+ }
1320
+
1321
+ [ Test ]
1322
+ public void TestShortenMantissaCase ( )
1323
+ {
1324
+ CheckShortenMantissaCase ( 9999888877776001UL , 1000 ) ;
1325
+ CheckShortenMantissaCase ( 1230000000000000UL , 80 ) ;
1326
+ CheckShortenMantissaCase ( 1230000000000075UL , 80 ) ;
1327
+ CheckShortenMantissaCase ( 1229999999999925UL , 80 ) ;
1328
+ CheckShortenMantissaCase ( 4409286553495543UL , 900 ) ;
1329
+ CheckShortenMantissaCase ( 4409286553495000UL , 1000 ) ;
1330
+ CheckShortenMantissaCase ( 4409286550000000UL , 81117294 ) ;
1331
+ CheckShortenMantissaCase ( 9010100000000001UL , 999999999999999L ) ;
1332
+ CheckShortenMantissaCase ( 8960196546869015UL , 1 ) ;
1333
+ CheckShortenMantissaCase ( 4700900091799999UL , 947076117508L ) ;
1334
+ CheckShortenMantissaCase ( 5876471737721999UL , 91086 ) ;
1335
+ CheckShortenMantissaCase ( 6336494570000000UL , 6092212816L ) ;
1336
+ CheckShortenMantissaCase ( 8960196546869011UL , 999999999999999L ) ;
1337
+ CheckShortenMantissaCase ( 1519453608576584UL , 3207L ) ;
1338
+ }
1339
+
1340
+ private static void CheckShortenMantissaCase ( ulong mantissa , ulong delta )
1341
+ {
1342
+ try
1343
+ {
1344
+ var bestSolution = ShortenMantissaDirect ( mantissa , delta ) ;
1345
+
1346
+ var test64 = Decimal64 . FromULong ( mantissa ) . ShortenMantissa ( delta , 0 ) . ToULong ( ) ;
1347
+
1348
+ if ( test64 != bestSolution )
1349
+ throw new Exception ( "The mantissa(=" + mantissa + ") and delta(=" + delta + ") produce test64(=" + test64 + ") != bestSolution(=" + bestSolution + ")." ) ;
1350
+ }
1351
+ catch ( Exception e )
1352
+ {
1353
+ throw new Exception ( "The mantissa(=" + mantissa + ") and delta(=" + delta + ") produce exception." , e ) ;
1354
+ }
1355
+ }
1356
+
1357
+ private static ulong ShortenMantissaDirect ( ulong mantissaIn , ulong deltaIn )
1358
+ {
1359
+ var mantissa = ( long ) mantissaIn ;
1360
+ var delta = ( long ) deltaIn ;
1361
+ var rgUp = mantissa + delta ;
1362
+ var rgDown = mantissa - delta ;
1363
+
1364
+ if ( mantissaIn <= DotNetImpl . MaxCoefficient / 10 || mantissaIn > DotNetImpl . MaxCoefficient )
1365
+ throw new ArgumentException ( "The mantissa(=" + mantissa + ") must be in (" + DotNetImpl . MaxCoefficient / 10 + ".." + DotNetImpl . MaxCoefficient + "] range" ) ;
1366
+
1367
+ long bestSolution = long . MinValue ;
1368
+ if ( rgDown > 0 )
1369
+ {
1370
+ var mUp = ( mantissa / 10 ) * 10 ;
1371
+ uint mFactor = 1 ;
1372
+
1373
+ long bestDifference = long . MaxValue ;
1374
+ int bestPosition = - 1 ;
1375
+
1376
+ for ( int replacePosition = 0 ;
1377
+ replacePosition < Decimal64 . MaxSignificandDigits + 1 ;
1378
+ ++ replacePosition , mUp = ( mUp / 100 ) * 10 , mFactor *= 10 )
1379
+ {
1380
+ for ( uint d = 0 ; d < 10 ; ++ d )
1381
+ {
1382
+ var mTest = ( mUp + d ) * mFactor ;
1383
+ if ( rgDown <= mTest && mTest <= rgUp )
1384
+ {
1385
+ var md = Math . Abs ( mantissa - mTest ) ;
1386
+ if ( bestPosition < replacePosition ||
1387
+ ( bestPosition == replacePosition && bestDifference >= md ) )
1388
+ {
1389
+ bestPosition = replacePosition ;
1390
+ bestDifference = md ;
1391
+ bestSolution = mTest ;
1392
+ }
1393
+ }
1394
+ }
1395
+ }
1396
+ }
1397
+ else
1398
+ {
1399
+ bestSolution = 0 ;
1400
+ }
1401
+
1402
+ return ( ulong ) bestSolution ;
1403
+ }
1404
+
1405
+ private static ulong GenerateMantissa ( Random random , int minimalLength )
1406
+ {
1407
+ int mLen = ( 1 + random . Next ( Decimal64 . MaxSignificandDigits ) /*[1..16]*/ ) ;
1408
+ ulong m = 1 + ( ulong ) random . Next ( 9 ) ;
1409
+ int i = 1 ;
1410
+ for ( ; i < mLen ; ++ i )
1411
+ m = m * 10 + ( ulong ) random . Next ( 10 ) ;
1412
+ for ( ; i < minimalLength ; ++ i )
1413
+ m = m * 10 ;
1414
+ return m ;
1415
+ }
1416
+
1272
1417
readonly int N = 5000000 ;
1273
1418
1274
1419
static void Main ( )
0 commit comments