├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock ├── doc ├── doc.md ├── example1.php └── internals │ └── why-sub-works.txt ├── phpunit.xml ├── src └── mersenne_twister.php └── tests ├── checksums ├── phpunit └── tests │ └── TwisterTest.php └── test-php-versions /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0 2 | 3 | * Minor changes to allow the library to work with PHP 8. 4 | * Minimum version of PHP increased from 5.3.0 to 7.3.0. 5 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Everything in this repository is under the Creative Commons [CC0 1.0 2 | licence](https://creativecommons.org/publicdomain/zero/1.0/). 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This repository contains a PHP implementation of the Mersenne Twister. 4 | Documentation is [here](doc/doc.md). 5 | 6 | ## Versioning 7 | 8 | This software uses 9 | [Semantic Versioning][semver]. 10 | 11 | [semver]: http://semver.org/ 12 | 13 | ## Notes 14 | 15 | The code is not 16 | representative of how I currently 17 | write PHP, but the software is useful nonetheless. 18 | I have brought it into GitHub to make 19 | it easier for the community to contribute. 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruafozy/mersenne-twister", 3 | "description": "Pure-PHP Mersenne Twister", 4 | "homepage": "https://github.com/ruafozy/php-mersenne-twister", 5 | "license": "MIT", 6 | "require": { 7 | "php": ">=7.3.0" 8 | }, 9 | "autoload": { 10 | "files": [ 11 | "src/mersenne_twister.php" 12 | ] 13 | }, 14 | "require-dev": { 15 | "phpunit/phpunit": "~9" 16 | }, 17 | "keywords": [ 18 | "PRNG", "random", "mersenne" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "33760a4bc095d98bcbb7747362fd4379", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "doctrine/instantiator", 12 | "version": "1.5.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/doctrine/instantiator.git", 16 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", 21 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^7.1 || ^8.0" 26 | }, 27 | "require-dev": { 28 | "doctrine/coding-standard": "^9 || ^11", 29 | "ext-pdo": "*", 30 | "ext-phar": "*", 31 | "phpbench/phpbench": "^0.16 || ^1", 32 | "phpstan/phpstan": "^1.4", 33 | "phpstan/phpstan-phpunit": "^1", 34 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", 35 | "vimeo/psalm": "^4.30 || ^5.4" 36 | }, 37 | "type": "library", 38 | "autoload": { 39 | "psr-4": { 40 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 41 | } 42 | }, 43 | "notification-url": "https://packagist.org/downloads/", 44 | "license": [ 45 | "MIT" 46 | ], 47 | "authors": [ 48 | { 49 | "name": "Marco Pivetta", 50 | "email": "ocramius@gmail.com", 51 | "homepage": "https://ocramius.github.io/" 52 | } 53 | ], 54 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 55 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 56 | "keywords": [ 57 | "constructor", 58 | "instantiate" 59 | ], 60 | "support": { 61 | "issues": "https://github.com/doctrine/instantiator/issues", 62 | "source": "https://github.com/doctrine/instantiator/tree/1.5.0" 63 | }, 64 | "funding": [ 65 | { 66 | "url": "https://www.doctrine-project.org/sponsorship.html", 67 | "type": "custom" 68 | }, 69 | { 70 | "url": "https://www.patreon.com/phpdoctrine", 71 | "type": "patreon" 72 | }, 73 | { 74 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", 75 | "type": "tidelift" 76 | } 77 | ], 78 | "time": "2022-12-30T00:15:36+00:00" 79 | }, 80 | { 81 | "name": "myclabs/deep-copy", 82 | "version": "1.11.1", 83 | "source": { 84 | "type": "git", 85 | "url": "https://github.com/myclabs/DeepCopy.git", 86 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" 87 | }, 88 | "dist": { 89 | "type": "zip", 90 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 91 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 92 | "shasum": "" 93 | }, 94 | "require": { 95 | "php": "^7.1 || ^8.0" 96 | }, 97 | "conflict": { 98 | "doctrine/collections": "<1.6.8", 99 | "doctrine/common": "<2.13.3 || >=3,<3.2.2" 100 | }, 101 | "require-dev": { 102 | "doctrine/collections": "^1.6.8", 103 | "doctrine/common": "^2.13.3 || ^3.2.2", 104 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 105 | }, 106 | "type": "library", 107 | "autoload": { 108 | "files": [ 109 | "src/DeepCopy/deep_copy.php" 110 | ], 111 | "psr-4": { 112 | "DeepCopy\\": "src/DeepCopy/" 113 | } 114 | }, 115 | "notification-url": "https://packagist.org/downloads/", 116 | "license": [ 117 | "MIT" 118 | ], 119 | "description": "Create deep copies (clones) of your objects", 120 | "keywords": [ 121 | "clone", 122 | "copy", 123 | "duplicate", 124 | "object", 125 | "object graph" 126 | ], 127 | "support": { 128 | "issues": "https://github.com/myclabs/DeepCopy/issues", 129 | "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" 130 | }, 131 | "funding": [ 132 | { 133 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 134 | "type": "tidelift" 135 | } 136 | ], 137 | "time": "2023-03-08T13:26:56+00:00" 138 | }, 139 | { 140 | "name": "nikic/php-parser", 141 | "version": "v4.15.4", 142 | "source": { 143 | "type": "git", 144 | "url": "https://github.com/nikic/PHP-Parser.git", 145 | "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" 146 | }, 147 | "dist": { 148 | "type": "zip", 149 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", 150 | "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", 151 | "shasum": "" 152 | }, 153 | "require": { 154 | "ext-tokenizer": "*", 155 | "php": ">=7.0" 156 | }, 157 | "require-dev": { 158 | "ircmaxell/php-yacc": "^0.0.7", 159 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" 160 | }, 161 | "bin": [ 162 | "bin/php-parse" 163 | ], 164 | "type": "library", 165 | "extra": { 166 | "branch-alias": { 167 | "dev-master": "4.9-dev" 168 | } 169 | }, 170 | "autoload": { 171 | "psr-4": { 172 | "PhpParser\\": "lib/PhpParser" 173 | } 174 | }, 175 | "notification-url": "https://packagist.org/downloads/", 176 | "license": [ 177 | "BSD-3-Clause" 178 | ], 179 | "authors": [ 180 | { 181 | "name": "Nikita Popov" 182 | } 183 | ], 184 | "description": "A PHP parser written in PHP", 185 | "keywords": [ 186 | "parser", 187 | "php" 188 | ], 189 | "support": { 190 | "issues": "https://github.com/nikic/PHP-Parser/issues", 191 | "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" 192 | }, 193 | "time": "2023-03-05T19:49:14+00:00" 194 | }, 195 | { 196 | "name": "phar-io/manifest", 197 | "version": "2.0.3", 198 | "source": { 199 | "type": "git", 200 | "url": "https://github.com/phar-io/manifest.git", 201 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53" 202 | }, 203 | "dist": { 204 | "type": "zip", 205 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", 206 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53", 207 | "shasum": "" 208 | }, 209 | "require": { 210 | "ext-dom": "*", 211 | "ext-phar": "*", 212 | "ext-xmlwriter": "*", 213 | "phar-io/version": "^3.0.1", 214 | "php": "^7.2 || ^8.0" 215 | }, 216 | "type": "library", 217 | "extra": { 218 | "branch-alias": { 219 | "dev-master": "2.0.x-dev" 220 | } 221 | }, 222 | "autoload": { 223 | "classmap": [ 224 | "src/" 225 | ] 226 | }, 227 | "notification-url": "https://packagist.org/downloads/", 228 | "license": [ 229 | "BSD-3-Clause" 230 | ], 231 | "authors": [ 232 | { 233 | "name": "Arne Blankerts", 234 | "email": "arne@blankerts.de", 235 | "role": "Developer" 236 | }, 237 | { 238 | "name": "Sebastian Heuer", 239 | "email": "sebastian@phpeople.de", 240 | "role": "Developer" 241 | }, 242 | { 243 | "name": "Sebastian Bergmann", 244 | "email": "sebastian@phpunit.de", 245 | "role": "Developer" 246 | } 247 | ], 248 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 249 | "support": { 250 | "issues": "https://github.com/phar-io/manifest/issues", 251 | "source": "https://github.com/phar-io/manifest/tree/2.0.3" 252 | }, 253 | "time": "2021-07-20T11:28:43+00:00" 254 | }, 255 | { 256 | "name": "phar-io/version", 257 | "version": "3.2.1", 258 | "source": { 259 | "type": "git", 260 | "url": "https://github.com/phar-io/version.git", 261 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 262 | }, 263 | "dist": { 264 | "type": "zip", 265 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 266 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 267 | "shasum": "" 268 | }, 269 | "require": { 270 | "php": "^7.2 || ^8.0" 271 | }, 272 | "type": "library", 273 | "autoload": { 274 | "classmap": [ 275 | "src/" 276 | ] 277 | }, 278 | "notification-url": "https://packagist.org/downloads/", 279 | "license": [ 280 | "BSD-3-Clause" 281 | ], 282 | "authors": [ 283 | { 284 | "name": "Arne Blankerts", 285 | "email": "arne@blankerts.de", 286 | "role": "Developer" 287 | }, 288 | { 289 | "name": "Sebastian Heuer", 290 | "email": "sebastian@phpeople.de", 291 | "role": "Developer" 292 | }, 293 | { 294 | "name": "Sebastian Bergmann", 295 | "email": "sebastian@phpunit.de", 296 | "role": "Developer" 297 | } 298 | ], 299 | "description": "Library for handling version information and constraints", 300 | "support": { 301 | "issues": "https://github.com/phar-io/version/issues", 302 | "source": "https://github.com/phar-io/version/tree/3.2.1" 303 | }, 304 | "time": "2022-02-21T01:04:05+00:00" 305 | }, 306 | { 307 | "name": "phpunit/php-code-coverage", 308 | "version": "9.2.26", 309 | "source": { 310 | "type": "git", 311 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 312 | "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" 313 | }, 314 | "dist": { 315 | "type": "zip", 316 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", 317 | "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", 318 | "shasum": "" 319 | }, 320 | "require": { 321 | "ext-dom": "*", 322 | "ext-libxml": "*", 323 | "ext-xmlwriter": "*", 324 | "nikic/php-parser": "^4.15", 325 | "php": ">=7.3", 326 | "phpunit/php-file-iterator": "^3.0.3", 327 | "phpunit/php-text-template": "^2.0.2", 328 | "sebastian/code-unit-reverse-lookup": "^2.0.2", 329 | "sebastian/complexity": "^2.0", 330 | "sebastian/environment": "^5.1.2", 331 | "sebastian/lines-of-code": "^1.0.3", 332 | "sebastian/version": "^3.0.1", 333 | "theseer/tokenizer": "^1.2.0" 334 | }, 335 | "require-dev": { 336 | "phpunit/phpunit": "^9.3" 337 | }, 338 | "suggest": { 339 | "ext-pcov": "PHP extension that provides line coverage", 340 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 341 | }, 342 | "type": "library", 343 | "extra": { 344 | "branch-alias": { 345 | "dev-master": "9.2-dev" 346 | } 347 | }, 348 | "autoload": { 349 | "classmap": [ 350 | "src/" 351 | ] 352 | }, 353 | "notification-url": "https://packagist.org/downloads/", 354 | "license": [ 355 | "BSD-3-Clause" 356 | ], 357 | "authors": [ 358 | { 359 | "name": "Sebastian Bergmann", 360 | "email": "sebastian@phpunit.de", 361 | "role": "lead" 362 | } 363 | ], 364 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 365 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 366 | "keywords": [ 367 | "coverage", 368 | "testing", 369 | "xunit" 370 | ], 371 | "support": { 372 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 373 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" 374 | }, 375 | "funding": [ 376 | { 377 | "url": "https://github.com/sebastianbergmann", 378 | "type": "github" 379 | } 380 | ], 381 | "time": "2023-03-06T12:58:08+00:00" 382 | }, 383 | { 384 | "name": "phpunit/php-file-iterator", 385 | "version": "3.0.6", 386 | "source": { 387 | "type": "git", 388 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 389 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" 390 | }, 391 | "dist": { 392 | "type": "zip", 393 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 394 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 395 | "shasum": "" 396 | }, 397 | "require": { 398 | "php": ">=7.3" 399 | }, 400 | "require-dev": { 401 | "phpunit/phpunit": "^9.3" 402 | }, 403 | "type": "library", 404 | "extra": { 405 | "branch-alias": { 406 | "dev-master": "3.0-dev" 407 | } 408 | }, 409 | "autoload": { 410 | "classmap": [ 411 | "src/" 412 | ] 413 | }, 414 | "notification-url": "https://packagist.org/downloads/", 415 | "license": [ 416 | "BSD-3-Clause" 417 | ], 418 | "authors": [ 419 | { 420 | "name": "Sebastian Bergmann", 421 | "email": "sebastian@phpunit.de", 422 | "role": "lead" 423 | } 424 | ], 425 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 426 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 427 | "keywords": [ 428 | "filesystem", 429 | "iterator" 430 | ], 431 | "support": { 432 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 433 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" 434 | }, 435 | "funding": [ 436 | { 437 | "url": "https://github.com/sebastianbergmann", 438 | "type": "github" 439 | } 440 | ], 441 | "time": "2021-12-02T12:48:52+00:00" 442 | }, 443 | { 444 | "name": "phpunit/php-invoker", 445 | "version": "3.1.1", 446 | "source": { 447 | "type": "git", 448 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 449 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" 450 | }, 451 | "dist": { 452 | "type": "zip", 453 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 454 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 455 | "shasum": "" 456 | }, 457 | "require": { 458 | "php": ">=7.3" 459 | }, 460 | "require-dev": { 461 | "ext-pcntl": "*", 462 | "phpunit/phpunit": "^9.3" 463 | }, 464 | "suggest": { 465 | "ext-pcntl": "*" 466 | }, 467 | "type": "library", 468 | "extra": { 469 | "branch-alias": { 470 | "dev-master": "3.1-dev" 471 | } 472 | }, 473 | "autoload": { 474 | "classmap": [ 475 | "src/" 476 | ] 477 | }, 478 | "notification-url": "https://packagist.org/downloads/", 479 | "license": [ 480 | "BSD-3-Clause" 481 | ], 482 | "authors": [ 483 | { 484 | "name": "Sebastian Bergmann", 485 | "email": "sebastian@phpunit.de", 486 | "role": "lead" 487 | } 488 | ], 489 | "description": "Invoke callables with a timeout", 490 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 491 | "keywords": [ 492 | "process" 493 | ], 494 | "support": { 495 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 496 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" 497 | }, 498 | "funding": [ 499 | { 500 | "url": "https://github.com/sebastianbergmann", 501 | "type": "github" 502 | } 503 | ], 504 | "time": "2020-09-28T05:58:55+00:00" 505 | }, 506 | { 507 | "name": "phpunit/php-text-template", 508 | "version": "2.0.4", 509 | "source": { 510 | "type": "git", 511 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 512 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" 513 | }, 514 | "dist": { 515 | "type": "zip", 516 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 517 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 518 | "shasum": "" 519 | }, 520 | "require": { 521 | "php": ">=7.3" 522 | }, 523 | "require-dev": { 524 | "phpunit/phpunit": "^9.3" 525 | }, 526 | "type": "library", 527 | "extra": { 528 | "branch-alias": { 529 | "dev-master": "2.0-dev" 530 | } 531 | }, 532 | "autoload": { 533 | "classmap": [ 534 | "src/" 535 | ] 536 | }, 537 | "notification-url": "https://packagist.org/downloads/", 538 | "license": [ 539 | "BSD-3-Clause" 540 | ], 541 | "authors": [ 542 | { 543 | "name": "Sebastian Bergmann", 544 | "email": "sebastian@phpunit.de", 545 | "role": "lead" 546 | } 547 | ], 548 | "description": "Simple template engine.", 549 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 550 | "keywords": [ 551 | "template" 552 | ], 553 | "support": { 554 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 555 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" 556 | }, 557 | "funding": [ 558 | { 559 | "url": "https://github.com/sebastianbergmann", 560 | "type": "github" 561 | } 562 | ], 563 | "time": "2020-10-26T05:33:50+00:00" 564 | }, 565 | { 566 | "name": "phpunit/php-timer", 567 | "version": "5.0.3", 568 | "source": { 569 | "type": "git", 570 | "url": "https://github.com/sebastianbergmann/php-timer.git", 571 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" 572 | }, 573 | "dist": { 574 | "type": "zip", 575 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 576 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 577 | "shasum": "" 578 | }, 579 | "require": { 580 | "php": ">=7.3" 581 | }, 582 | "require-dev": { 583 | "phpunit/phpunit": "^9.3" 584 | }, 585 | "type": "library", 586 | "extra": { 587 | "branch-alias": { 588 | "dev-master": "5.0-dev" 589 | } 590 | }, 591 | "autoload": { 592 | "classmap": [ 593 | "src/" 594 | ] 595 | }, 596 | "notification-url": "https://packagist.org/downloads/", 597 | "license": [ 598 | "BSD-3-Clause" 599 | ], 600 | "authors": [ 601 | { 602 | "name": "Sebastian Bergmann", 603 | "email": "sebastian@phpunit.de", 604 | "role": "lead" 605 | } 606 | ], 607 | "description": "Utility class for timing", 608 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 609 | "keywords": [ 610 | "timer" 611 | ], 612 | "support": { 613 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 614 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" 615 | }, 616 | "funding": [ 617 | { 618 | "url": "https://github.com/sebastianbergmann", 619 | "type": "github" 620 | } 621 | ], 622 | "time": "2020-10-26T13:16:10+00:00" 623 | }, 624 | { 625 | "name": "phpunit/phpunit", 626 | "version": "9.6.5", 627 | "source": { 628 | "type": "git", 629 | "url": "https://github.com/sebastianbergmann/phpunit.git", 630 | "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5" 631 | }, 632 | "dist": { 633 | "type": "zip", 634 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5", 635 | "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5", 636 | "shasum": "" 637 | }, 638 | "require": { 639 | "doctrine/instantiator": "^1.3.1 || ^2", 640 | "ext-dom": "*", 641 | "ext-json": "*", 642 | "ext-libxml": "*", 643 | "ext-mbstring": "*", 644 | "ext-xml": "*", 645 | "ext-xmlwriter": "*", 646 | "myclabs/deep-copy": "^1.10.1", 647 | "phar-io/manifest": "^2.0.3", 648 | "phar-io/version": "^3.0.2", 649 | "php": ">=7.3", 650 | "phpunit/php-code-coverage": "^9.2.13", 651 | "phpunit/php-file-iterator": "^3.0.5", 652 | "phpunit/php-invoker": "^3.1.1", 653 | "phpunit/php-text-template": "^2.0.3", 654 | "phpunit/php-timer": "^5.0.2", 655 | "sebastian/cli-parser": "^1.0.1", 656 | "sebastian/code-unit": "^1.0.6", 657 | "sebastian/comparator": "^4.0.8", 658 | "sebastian/diff": "^4.0.3", 659 | "sebastian/environment": "^5.1.3", 660 | "sebastian/exporter": "^4.0.5", 661 | "sebastian/global-state": "^5.0.1", 662 | "sebastian/object-enumerator": "^4.0.3", 663 | "sebastian/resource-operations": "^3.0.3", 664 | "sebastian/type": "^3.2", 665 | "sebastian/version": "^3.0.2" 666 | }, 667 | "suggest": { 668 | "ext-soap": "To be able to generate mocks based on WSDL files", 669 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 670 | }, 671 | "bin": [ 672 | "phpunit" 673 | ], 674 | "type": "library", 675 | "extra": { 676 | "branch-alias": { 677 | "dev-master": "9.6-dev" 678 | } 679 | }, 680 | "autoload": { 681 | "files": [ 682 | "src/Framework/Assert/Functions.php" 683 | ], 684 | "classmap": [ 685 | "src/" 686 | ] 687 | }, 688 | "notification-url": "https://packagist.org/downloads/", 689 | "license": [ 690 | "BSD-3-Clause" 691 | ], 692 | "authors": [ 693 | { 694 | "name": "Sebastian Bergmann", 695 | "email": "sebastian@phpunit.de", 696 | "role": "lead" 697 | } 698 | ], 699 | "description": "The PHP Unit Testing framework.", 700 | "homepage": "https://phpunit.de/", 701 | "keywords": [ 702 | "phpunit", 703 | "testing", 704 | "xunit" 705 | ], 706 | "support": { 707 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 708 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5" 709 | }, 710 | "funding": [ 711 | { 712 | "url": "https://phpunit.de/sponsors.html", 713 | "type": "custom" 714 | }, 715 | { 716 | "url": "https://github.com/sebastianbergmann", 717 | "type": "github" 718 | }, 719 | { 720 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 721 | "type": "tidelift" 722 | } 723 | ], 724 | "time": "2023-03-09T06:34:10+00:00" 725 | }, 726 | { 727 | "name": "sebastian/cli-parser", 728 | "version": "1.0.1", 729 | "source": { 730 | "type": "git", 731 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 732 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" 733 | }, 734 | "dist": { 735 | "type": "zip", 736 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", 737 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", 738 | "shasum": "" 739 | }, 740 | "require": { 741 | "php": ">=7.3" 742 | }, 743 | "require-dev": { 744 | "phpunit/phpunit": "^9.3" 745 | }, 746 | "type": "library", 747 | "extra": { 748 | "branch-alias": { 749 | "dev-master": "1.0-dev" 750 | } 751 | }, 752 | "autoload": { 753 | "classmap": [ 754 | "src/" 755 | ] 756 | }, 757 | "notification-url": "https://packagist.org/downloads/", 758 | "license": [ 759 | "BSD-3-Clause" 760 | ], 761 | "authors": [ 762 | { 763 | "name": "Sebastian Bergmann", 764 | "email": "sebastian@phpunit.de", 765 | "role": "lead" 766 | } 767 | ], 768 | "description": "Library for parsing CLI options", 769 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 770 | "support": { 771 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 772 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" 773 | }, 774 | "funding": [ 775 | { 776 | "url": "https://github.com/sebastianbergmann", 777 | "type": "github" 778 | } 779 | ], 780 | "time": "2020-09-28T06:08:49+00:00" 781 | }, 782 | { 783 | "name": "sebastian/code-unit", 784 | "version": "1.0.8", 785 | "source": { 786 | "type": "git", 787 | "url": "https://github.com/sebastianbergmann/code-unit.git", 788 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" 789 | }, 790 | "dist": { 791 | "type": "zip", 792 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", 793 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", 794 | "shasum": "" 795 | }, 796 | "require": { 797 | "php": ">=7.3" 798 | }, 799 | "require-dev": { 800 | "phpunit/phpunit": "^9.3" 801 | }, 802 | "type": "library", 803 | "extra": { 804 | "branch-alias": { 805 | "dev-master": "1.0-dev" 806 | } 807 | }, 808 | "autoload": { 809 | "classmap": [ 810 | "src/" 811 | ] 812 | }, 813 | "notification-url": "https://packagist.org/downloads/", 814 | "license": [ 815 | "BSD-3-Clause" 816 | ], 817 | "authors": [ 818 | { 819 | "name": "Sebastian Bergmann", 820 | "email": "sebastian@phpunit.de", 821 | "role": "lead" 822 | } 823 | ], 824 | "description": "Collection of value objects that represent the PHP code units", 825 | "homepage": "https://github.com/sebastianbergmann/code-unit", 826 | "support": { 827 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 828 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" 829 | }, 830 | "funding": [ 831 | { 832 | "url": "https://github.com/sebastianbergmann", 833 | "type": "github" 834 | } 835 | ], 836 | "time": "2020-10-26T13:08:54+00:00" 837 | }, 838 | { 839 | "name": "sebastian/code-unit-reverse-lookup", 840 | "version": "2.0.3", 841 | "source": { 842 | "type": "git", 843 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 844 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" 845 | }, 846 | "dist": { 847 | "type": "zip", 848 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 849 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 850 | "shasum": "" 851 | }, 852 | "require": { 853 | "php": ">=7.3" 854 | }, 855 | "require-dev": { 856 | "phpunit/phpunit": "^9.3" 857 | }, 858 | "type": "library", 859 | "extra": { 860 | "branch-alias": { 861 | "dev-master": "2.0-dev" 862 | } 863 | }, 864 | "autoload": { 865 | "classmap": [ 866 | "src/" 867 | ] 868 | }, 869 | "notification-url": "https://packagist.org/downloads/", 870 | "license": [ 871 | "BSD-3-Clause" 872 | ], 873 | "authors": [ 874 | { 875 | "name": "Sebastian Bergmann", 876 | "email": "sebastian@phpunit.de" 877 | } 878 | ], 879 | "description": "Looks up which function or method a line of code belongs to", 880 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 881 | "support": { 882 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 883 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" 884 | }, 885 | "funding": [ 886 | { 887 | "url": "https://github.com/sebastianbergmann", 888 | "type": "github" 889 | } 890 | ], 891 | "time": "2020-09-28T05:30:19+00:00" 892 | }, 893 | { 894 | "name": "sebastian/comparator", 895 | "version": "4.0.8", 896 | "source": { 897 | "type": "git", 898 | "url": "https://github.com/sebastianbergmann/comparator.git", 899 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a" 900 | }, 901 | "dist": { 902 | "type": "zip", 903 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", 904 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a", 905 | "shasum": "" 906 | }, 907 | "require": { 908 | "php": ">=7.3", 909 | "sebastian/diff": "^4.0", 910 | "sebastian/exporter": "^4.0" 911 | }, 912 | "require-dev": { 913 | "phpunit/phpunit": "^9.3" 914 | }, 915 | "type": "library", 916 | "extra": { 917 | "branch-alias": { 918 | "dev-master": "4.0-dev" 919 | } 920 | }, 921 | "autoload": { 922 | "classmap": [ 923 | "src/" 924 | ] 925 | }, 926 | "notification-url": "https://packagist.org/downloads/", 927 | "license": [ 928 | "BSD-3-Clause" 929 | ], 930 | "authors": [ 931 | { 932 | "name": "Sebastian Bergmann", 933 | "email": "sebastian@phpunit.de" 934 | }, 935 | { 936 | "name": "Jeff Welch", 937 | "email": "whatthejeff@gmail.com" 938 | }, 939 | { 940 | "name": "Volker Dusch", 941 | "email": "github@wallbash.com" 942 | }, 943 | { 944 | "name": "Bernhard Schussek", 945 | "email": "bschussek@2bepublished.at" 946 | } 947 | ], 948 | "description": "Provides the functionality to compare PHP values for equality", 949 | "homepage": "https://github.com/sebastianbergmann/comparator", 950 | "keywords": [ 951 | "comparator", 952 | "compare", 953 | "equality" 954 | ], 955 | "support": { 956 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 957 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" 958 | }, 959 | "funding": [ 960 | { 961 | "url": "https://github.com/sebastianbergmann", 962 | "type": "github" 963 | } 964 | ], 965 | "time": "2022-09-14T12:41:17+00:00" 966 | }, 967 | { 968 | "name": "sebastian/complexity", 969 | "version": "2.0.2", 970 | "source": { 971 | "type": "git", 972 | "url": "https://github.com/sebastianbergmann/complexity.git", 973 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" 974 | }, 975 | "dist": { 976 | "type": "zip", 977 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", 978 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", 979 | "shasum": "" 980 | }, 981 | "require": { 982 | "nikic/php-parser": "^4.7", 983 | "php": ">=7.3" 984 | }, 985 | "require-dev": { 986 | "phpunit/phpunit": "^9.3" 987 | }, 988 | "type": "library", 989 | "extra": { 990 | "branch-alias": { 991 | "dev-master": "2.0-dev" 992 | } 993 | }, 994 | "autoload": { 995 | "classmap": [ 996 | "src/" 997 | ] 998 | }, 999 | "notification-url": "https://packagist.org/downloads/", 1000 | "license": [ 1001 | "BSD-3-Clause" 1002 | ], 1003 | "authors": [ 1004 | { 1005 | "name": "Sebastian Bergmann", 1006 | "email": "sebastian@phpunit.de", 1007 | "role": "lead" 1008 | } 1009 | ], 1010 | "description": "Library for calculating the complexity of PHP code units", 1011 | "homepage": "https://github.com/sebastianbergmann/complexity", 1012 | "support": { 1013 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 1014 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" 1015 | }, 1016 | "funding": [ 1017 | { 1018 | "url": "https://github.com/sebastianbergmann", 1019 | "type": "github" 1020 | } 1021 | ], 1022 | "time": "2020-10-26T15:52:27+00:00" 1023 | }, 1024 | { 1025 | "name": "sebastian/diff", 1026 | "version": "4.0.4", 1027 | "source": { 1028 | "type": "git", 1029 | "url": "https://github.com/sebastianbergmann/diff.git", 1030 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" 1031 | }, 1032 | "dist": { 1033 | "type": "zip", 1034 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", 1035 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", 1036 | "shasum": "" 1037 | }, 1038 | "require": { 1039 | "php": ">=7.3" 1040 | }, 1041 | "require-dev": { 1042 | "phpunit/phpunit": "^9.3", 1043 | "symfony/process": "^4.2 || ^5" 1044 | }, 1045 | "type": "library", 1046 | "extra": { 1047 | "branch-alias": { 1048 | "dev-master": "4.0-dev" 1049 | } 1050 | }, 1051 | "autoload": { 1052 | "classmap": [ 1053 | "src/" 1054 | ] 1055 | }, 1056 | "notification-url": "https://packagist.org/downloads/", 1057 | "license": [ 1058 | "BSD-3-Clause" 1059 | ], 1060 | "authors": [ 1061 | { 1062 | "name": "Sebastian Bergmann", 1063 | "email": "sebastian@phpunit.de" 1064 | }, 1065 | { 1066 | "name": "Kore Nordmann", 1067 | "email": "mail@kore-nordmann.de" 1068 | } 1069 | ], 1070 | "description": "Diff implementation", 1071 | "homepage": "https://github.com/sebastianbergmann/diff", 1072 | "keywords": [ 1073 | "diff", 1074 | "udiff", 1075 | "unidiff", 1076 | "unified diff" 1077 | ], 1078 | "support": { 1079 | "issues": "https://github.com/sebastianbergmann/diff/issues", 1080 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" 1081 | }, 1082 | "funding": [ 1083 | { 1084 | "url": "https://github.com/sebastianbergmann", 1085 | "type": "github" 1086 | } 1087 | ], 1088 | "time": "2020-10-26T13:10:38+00:00" 1089 | }, 1090 | { 1091 | "name": "sebastian/environment", 1092 | "version": "5.1.5", 1093 | "source": { 1094 | "type": "git", 1095 | "url": "https://github.com/sebastianbergmann/environment.git", 1096 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" 1097 | }, 1098 | "dist": { 1099 | "type": "zip", 1100 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 1101 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 1102 | "shasum": "" 1103 | }, 1104 | "require": { 1105 | "php": ">=7.3" 1106 | }, 1107 | "require-dev": { 1108 | "phpunit/phpunit": "^9.3" 1109 | }, 1110 | "suggest": { 1111 | "ext-posix": "*" 1112 | }, 1113 | "type": "library", 1114 | "extra": { 1115 | "branch-alias": { 1116 | "dev-master": "5.1-dev" 1117 | } 1118 | }, 1119 | "autoload": { 1120 | "classmap": [ 1121 | "src/" 1122 | ] 1123 | }, 1124 | "notification-url": "https://packagist.org/downloads/", 1125 | "license": [ 1126 | "BSD-3-Clause" 1127 | ], 1128 | "authors": [ 1129 | { 1130 | "name": "Sebastian Bergmann", 1131 | "email": "sebastian@phpunit.de" 1132 | } 1133 | ], 1134 | "description": "Provides functionality to handle HHVM/PHP environments", 1135 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1136 | "keywords": [ 1137 | "Xdebug", 1138 | "environment", 1139 | "hhvm" 1140 | ], 1141 | "support": { 1142 | "issues": "https://github.com/sebastianbergmann/environment/issues", 1143 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" 1144 | }, 1145 | "funding": [ 1146 | { 1147 | "url": "https://github.com/sebastianbergmann", 1148 | "type": "github" 1149 | } 1150 | ], 1151 | "time": "2023-02-03T06:03:51+00:00" 1152 | }, 1153 | { 1154 | "name": "sebastian/exporter", 1155 | "version": "4.0.5", 1156 | "source": { 1157 | "type": "git", 1158 | "url": "https://github.com/sebastianbergmann/exporter.git", 1159 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" 1160 | }, 1161 | "dist": { 1162 | "type": "zip", 1163 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 1164 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 1165 | "shasum": "" 1166 | }, 1167 | "require": { 1168 | "php": ">=7.3", 1169 | "sebastian/recursion-context": "^4.0" 1170 | }, 1171 | "require-dev": { 1172 | "ext-mbstring": "*", 1173 | "phpunit/phpunit": "^9.3" 1174 | }, 1175 | "type": "library", 1176 | "extra": { 1177 | "branch-alias": { 1178 | "dev-master": "4.0-dev" 1179 | } 1180 | }, 1181 | "autoload": { 1182 | "classmap": [ 1183 | "src/" 1184 | ] 1185 | }, 1186 | "notification-url": "https://packagist.org/downloads/", 1187 | "license": [ 1188 | "BSD-3-Clause" 1189 | ], 1190 | "authors": [ 1191 | { 1192 | "name": "Sebastian Bergmann", 1193 | "email": "sebastian@phpunit.de" 1194 | }, 1195 | { 1196 | "name": "Jeff Welch", 1197 | "email": "whatthejeff@gmail.com" 1198 | }, 1199 | { 1200 | "name": "Volker Dusch", 1201 | "email": "github@wallbash.com" 1202 | }, 1203 | { 1204 | "name": "Adam Harvey", 1205 | "email": "aharvey@php.net" 1206 | }, 1207 | { 1208 | "name": "Bernhard Schussek", 1209 | "email": "bschussek@gmail.com" 1210 | } 1211 | ], 1212 | "description": "Provides the functionality to export PHP variables for visualization", 1213 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 1214 | "keywords": [ 1215 | "export", 1216 | "exporter" 1217 | ], 1218 | "support": { 1219 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 1220 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" 1221 | }, 1222 | "funding": [ 1223 | { 1224 | "url": "https://github.com/sebastianbergmann", 1225 | "type": "github" 1226 | } 1227 | ], 1228 | "time": "2022-09-14T06:03:37+00:00" 1229 | }, 1230 | { 1231 | "name": "sebastian/global-state", 1232 | "version": "5.0.5", 1233 | "source": { 1234 | "type": "git", 1235 | "url": "https://github.com/sebastianbergmann/global-state.git", 1236 | "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" 1237 | }, 1238 | "dist": { 1239 | "type": "zip", 1240 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", 1241 | "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", 1242 | "shasum": "" 1243 | }, 1244 | "require": { 1245 | "php": ">=7.3", 1246 | "sebastian/object-reflector": "^2.0", 1247 | "sebastian/recursion-context": "^4.0" 1248 | }, 1249 | "require-dev": { 1250 | "ext-dom": "*", 1251 | "phpunit/phpunit": "^9.3" 1252 | }, 1253 | "suggest": { 1254 | "ext-uopz": "*" 1255 | }, 1256 | "type": "library", 1257 | "extra": { 1258 | "branch-alias": { 1259 | "dev-master": "5.0-dev" 1260 | } 1261 | }, 1262 | "autoload": { 1263 | "classmap": [ 1264 | "src/" 1265 | ] 1266 | }, 1267 | "notification-url": "https://packagist.org/downloads/", 1268 | "license": [ 1269 | "BSD-3-Clause" 1270 | ], 1271 | "authors": [ 1272 | { 1273 | "name": "Sebastian Bergmann", 1274 | "email": "sebastian@phpunit.de" 1275 | } 1276 | ], 1277 | "description": "Snapshotting of global state", 1278 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1279 | "keywords": [ 1280 | "global state" 1281 | ], 1282 | "support": { 1283 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 1284 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" 1285 | }, 1286 | "funding": [ 1287 | { 1288 | "url": "https://github.com/sebastianbergmann", 1289 | "type": "github" 1290 | } 1291 | ], 1292 | "time": "2022-02-14T08:28:10+00:00" 1293 | }, 1294 | { 1295 | "name": "sebastian/lines-of-code", 1296 | "version": "1.0.3", 1297 | "source": { 1298 | "type": "git", 1299 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 1300 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" 1301 | }, 1302 | "dist": { 1303 | "type": "zip", 1304 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", 1305 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", 1306 | "shasum": "" 1307 | }, 1308 | "require": { 1309 | "nikic/php-parser": "^4.6", 1310 | "php": ">=7.3" 1311 | }, 1312 | "require-dev": { 1313 | "phpunit/phpunit": "^9.3" 1314 | }, 1315 | "type": "library", 1316 | "extra": { 1317 | "branch-alias": { 1318 | "dev-master": "1.0-dev" 1319 | } 1320 | }, 1321 | "autoload": { 1322 | "classmap": [ 1323 | "src/" 1324 | ] 1325 | }, 1326 | "notification-url": "https://packagist.org/downloads/", 1327 | "license": [ 1328 | "BSD-3-Clause" 1329 | ], 1330 | "authors": [ 1331 | { 1332 | "name": "Sebastian Bergmann", 1333 | "email": "sebastian@phpunit.de", 1334 | "role": "lead" 1335 | } 1336 | ], 1337 | "description": "Library for counting the lines of code in PHP source code", 1338 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 1339 | "support": { 1340 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 1341 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" 1342 | }, 1343 | "funding": [ 1344 | { 1345 | "url": "https://github.com/sebastianbergmann", 1346 | "type": "github" 1347 | } 1348 | ], 1349 | "time": "2020-11-28T06:42:11+00:00" 1350 | }, 1351 | { 1352 | "name": "sebastian/object-enumerator", 1353 | "version": "4.0.4", 1354 | "source": { 1355 | "type": "git", 1356 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1357 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" 1358 | }, 1359 | "dist": { 1360 | "type": "zip", 1361 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", 1362 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", 1363 | "shasum": "" 1364 | }, 1365 | "require": { 1366 | "php": ">=7.3", 1367 | "sebastian/object-reflector": "^2.0", 1368 | "sebastian/recursion-context": "^4.0" 1369 | }, 1370 | "require-dev": { 1371 | "phpunit/phpunit": "^9.3" 1372 | }, 1373 | "type": "library", 1374 | "extra": { 1375 | "branch-alias": { 1376 | "dev-master": "4.0-dev" 1377 | } 1378 | }, 1379 | "autoload": { 1380 | "classmap": [ 1381 | "src/" 1382 | ] 1383 | }, 1384 | "notification-url": "https://packagist.org/downloads/", 1385 | "license": [ 1386 | "BSD-3-Clause" 1387 | ], 1388 | "authors": [ 1389 | { 1390 | "name": "Sebastian Bergmann", 1391 | "email": "sebastian@phpunit.de" 1392 | } 1393 | ], 1394 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1395 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1396 | "support": { 1397 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 1398 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" 1399 | }, 1400 | "funding": [ 1401 | { 1402 | "url": "https://github.com/sebastianbergmann", 1403 | "type": "github" 1404 | } 1405 | ], 1406 | "time": "2020-10-26T13:12:34+00:00" 1407 | }, 1408 | { 1409 | "name": "sebastian/object-reflector", 1410 | "version": "2.0.4", 1411 | "source": { 1412 | "type": "git", 1413 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1414 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" 1415 | }, 1416 | "dist": { 1417 | "type": "zip", 1418 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1419 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1420 | "shasum": "" 1421 | }, 1422 | "require": { 1423 | "php": ">=7.3" 1424 | }, 1425 | "require-dev": { 1426 | "phpunit/phpunit": "^9.3" 1427 | }, 1428 | "type": "library", 1429 | "extra": { 1430 | "branch-alias": { 1431 | "dev-master": "2.0-dev" 1432 | } 1433 | }, 1434 | "autoload": { 1435 | "classmap": [ 1436 | "src/" 1437 | ] 1438 | }, 1439 | "notification-url": "https://packagist.org/downloads/", 1440 | "license": [ 1441 | "BSD-3-Clause" 1442 | ], 1443 | "authors": [ 1444 | { 1445 | "name": "Sebastian Bergmann", 1446 | "email": "sebastian@phpunit.de" 1447 | } 1448 | ], 1449 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1450 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1451 | "support": { 1452 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 1453 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" 1454 | }, 1455 | "funding": [ 1456 | { 1457 | "url": "https://github.com/sebastianbergmann", 1458 | "type": "github" 1459 | } 1460 | ], 1461 | "time": "2020-10-26T13:14:26+00:00" 1462 | }, 1463 | { 1464 | "name": "sebastian/recursion-context", 1465 | "version": "4.0.5", 1466 | "source": { 1467 | "type": "git", 1468 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1469 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" 1470 | }, 1471 | "dist": { 1472 | "type": "zip", 1473 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 1474 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 1475 | "shasum": "" 1476 | }, 1477 | "require": { 1478 | "php": ">=7.3" 1479 | }, 1480 | "require-dev": { 1481 | "phpunit/phpunit": "^9.3" 1482 | }, 1483 | "type": "library", 1484 | "extra": { 1485 | "branch-alias": { 1486 | "dev-master": "4.0-dev" 1487 | } 1488 | }, 1489 | "autoload": { 1490 | "classmap": [ 1491 | "src/" 1492 | ] 1493 | }, 1494 | "notification-url": "https://packagist.org/downloads/", 1495 | "license": [ 1496 | "BSD-3-Clause" 1497 | ], 1498 | "authors": [ 1499 | { 1500 | "name": "Sebastian Bergmann", 1501 | "email": "sebastian@phpunit.de" 1502 | }, 1503 | { 1504 | "name": "Jeff Welch", 1505 | "email": "whatthejeff@gmail.com" 1506 | }, 1507 | { 1508 | "name": "Adam Harvey", 1509 | "email": "aharvey@php.net" 1510 | } 1511 | ], 1512 | "description": "Provides functionality to recursively process PHP variables", 1513 | "homepage": "https://github.com/sebastianbergmann/recursion-context", 1514 | "support": { 1515 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 1516 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" 1517 | }, 1518 | "funding": [ 1519 | { 1520 | "url": "https://github.com/sebastianbergmann", 1521 | "type": "github" 1522 | } 1523 | ], 1524 | "time": "2023-02-03T06:07:39+00:00" 1525 | }, 1526 | { 1527 | "name": "sebastian/resource-operations", 1528 | "version": "3.0.3", 1529 | "source": { 1530 | "type": "git", 1531 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1532 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" 1533 | }, 1534 | "dist": { 1535 | "type": "zip", 1536 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 1537 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 1538 | "shasum": "" 1539 | }, 1540 | "require": { 1541 | "php": ">=7.3" 1542 | }, 1543 | "require-dev": { 1544 | "phpunit/phpunit": "^9.0" 1545 | }, 1546 | "type": "library", 1547 | "extra": { 1548 | "branch-alias": { 1549 | "dev-master": "3.0-dev" 1550 | } 1551 | }, 1552 | "autoload": { 1553 | "classmap": [ 1554 | "src/" 1555 | ] 1556 | }, 1557 | "notification-url": "https://packagist.org/downloads/", 1558 | "license": [ 1559 | "BSD-3-Clause" 1560 | ], 1561 | "authors": [ 1562 | { 1563 | "name": "Sebastian Bergmann", 1564 | "email": "sebastian@phpunit.de" 1565 | } 1566 | ], 1567 | "description": "Provides a list of PHP built-in functions that operate on resources", 1568 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1569 | "support": { 1570 | "issues": "https://github.com/sebastianbergmann/resource-operations/issues", 1571 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" 1572 | }, 1573 | "funding": [ 1574 | { 1575 | "url": "https://github.com/sebastianbergmann", 1576 | "type": "github" 1577 | } 1578 | ], 1579 | "time": "2020-09-28T06:45:17+00:00" 1580 | }, 1581 | { 1582 | "name": "sebastian/type", 1583 | "version": "3.2.1", 1584 | "source": { 1585 | "type": "git", 1586 | "url": "https://github.com/sebastianbergmann/type.git", 1587 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" 1588 | }, 1589 | "dist": { 1590 | "type": "zip", 1591 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 1592 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 1593 | "shasum": "" 1594 | }, 1595 | "require": { 1596 | "php": ">=7.3" 1597 | }, 1598 | "require-dev": { 1599 | "phpunit/phpunit": "^9.5" 1600 | }, 1601 | "type": "library", 1602 | "extra": { 1603 | "branch-alias": { 1604 | "dev-master": "3.2-dev" 1605 | } 1606 | }, 1607 | "autoload": { 1608 | "classmap": [ 1609 | "src/" 1610 | ] 1611 | }, 1612 | "notification-url": "https://packagist.org/downloads/", 1613 | "license": [ 1614 | "BSD-3-Clause" 1615 | ], 1616 | "authors": [ 1617 | { 1618 | "name": "Sebastian Bergmann", 1619 | "email": "sebastian@phpunit.de", 1620 | "role": "lead" 1621 | } 1622 | ], 1623 | "description": "Collection of value objects that represent the types of the PHP type system", 1624 | "homepage": "https://github.com/sebastianbergmann/type", 1625 | "support": { 1626 | "issues": "https://github.com/sebastianbergmann/type/issues", 1627 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" 1628 | }, 1629 | "funding": [ 1630 | { 1631 | "url": "https://github.com/sebastianbergmann", 1632 | "type": "github" 1633 | } 1634 | ], 1635 | "time": "2023-02-03T06:13:03+00:00" 1636 | }, 1637 | { 1638 | "name": "sebastian/version", 1639 | "version": "3.0.2", 1640 | "source": { 1641 | "type": "git", 1642 | "url": "https://github.com/sebastianbergmann/version.git", 1643 | "reference": "c6c1022351a901512170118436c764e473f6de8c" 1644 | }, 1645 | "dist": { 1646 | "type": "zip", 1647 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", 1648 | "reference": "c6c1022351a901512170118436c764e473f6de8c", 1649 | "shasum": "" 1650 | }, 1651 | "require": { 1652 | "php": ">=7.3" 1653 | }, 1654 | "type": "library", 1655 | "extra": { 1656 | "branch-alias": { 1657 | "dev-master": "3.0-dev" 1658 | } 1659 | }, 1660 | "autoload": { 1661 | "classmap": [ 1662 | "src/" 1663 | ] 1664 | }, 1665 | "notification-url": "https://packagist.org/downloads/", 1666 | "license": [ 1667 | "BSD-3-Clause" 1668 | ], 1669 | "authors": [ 1670 | { 1671 | "name": "Sebastian Bergmann", 1672 | "email": "sebastian@phpunit.de", 1673 | "role": "lead" 1674 | } 1675 | ], 1676 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1677 | "homepage": "https://github.com/sebastianbergmann/version", 1678 | "support": { 1679 | "issues": "https://github.com/sebastianbergmann/version/issues", 1680 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" 1681 | }, 1682 | "funding": [ 1683 | { 1684 | "url": "https://github.com/sebastianbergmann", 1685 | "type": "github" 1686 | } 1687 | ], 1688 | "time": "2020-09-28T06:39:44+00:00" 1689 | }, 1690 | { 1691 | "name": "theseer/tokenizer", 1692 | "version": "1.2.1", 1693 | "source": { 1694 | "type": "git", 1695 | "url": "https://github.com/theseer/tokenizer.git", 1696 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" 1697 | }, 1698 | "dist": { 1699 | "type": "zip", 1700 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", 1701 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", 1702 | "shasum": "" 1703 | }, 1704 | "require": { 1705 | "ext-dom": "*", 1706 | "ext-tokenizer": "*", 1707 | "ext-xmlwriter": "*", 1708 | "php": "^7.2 || ^8.0" 1709 | }, 1710 | "type": "library", 1711 | "autoload": { 1712 | "classmap": [ 1713 | "src/" 1714 | ] 1715 | }, 1716 | "notification-url": "https://packagist.org/downloads/", 1717 | "license": [ 1718 | "BSD-3-Clause" 1719 | ], 1720 | "authors": [ 1721 | { 1722 | "name": "Arne Blankerts", 1723 | "email": "arne@blankerts.de", 1724 | "role": "Developer" 1725 | } 1726 | ], 1727 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1728 | "support": { 1729 | "issues": "https://github.com/theseer/tokenizer/issues", 1730 | "source": "https://github.com/theseer/tokenizer/tree/1.2.1" 1731 | }, 1732 | "funding": [ 1733 | { 1734 | "url": "https://github.com/theseer", 1735 | "type": "github" 1736 | } 1737 | ], 1738 | "time": "2021-07-28T10:34:58+00:00" 1739 | } 1740 | ], 1741 | "aliases": [], 1742 | "minimum-stability": "stable", 1743 | "stability-flags": [], 1744 | "prefer-stable": false, 1745 | "prefer-lowest": false, 1746 | "platform": { 1747 | "php": ">=7.3.0" 1748 | }, 1749 | "platform-dev": [], 1750 | "plugin-api-version": "2.3.0" 1751 | } 1752 | -------------------------------------------------------------------------------- /doc/doc.md: -------------------------------------------------------------------------------- 1 | All the necessary documentation is here: 2 | 3 | > http://kingfisher.nfshost.com/sw/twister/ 4 | 5 | If you are using this library via 6 | [Composer](https://getcomposer.org/) 7 | then 8 | please note the following modifications to 9 | that documentation: 10 | 11 | * There is no need to load the library with `require_once`. 12 | -------------------------------------------------------------------------------- /doc/example1.php: -------------------------------------------------------------------------------- 1 | int32() !== $twister2->int32()) 18 | print "They're different -- " . 19 | "this is not supposed to happen!\n"; 20 | 21 | #-------------------------------------------- 22 | 23 | $num_iters = 1000; 24 | 25 | $twister3 = new twister(42); 26 | $saved = serialize($twister3); 27 | 28 | $sum = 0; 29 | for($i = 0; $i < $num_iters; $i++) 30 | $sum += $twister3->rangereal_halfopen(10, 20); 31 | /* 32 | the call to rangereal_halfopen produces a 33 | floating-point number >= 10 and < 20 34 | */ 35 | 36 | print "This is the average, " . 37 | "which should be about 15: " . 38 | ($sum / $num_iters) . "\n"; 39 | 40 | $twister3 = unserialize($saved); 41 | 42 | # run the loop again 43 | # 44 | $sum = 0; 45 | for($i = 0; $i < $num_iters; $i++) 46 | $sum += $twister3->rangereal_halfopen(10, 20); 47 | 48 | print "This is the average again, " . 49 | "which should be the same as before: " . 50 | ($sum / $num_iters) . "\n"; 51 | 52 | #-------------------------------------------- 53 | 54 | $twister4 = new twister; 55 | 56 | $twister4->init_with_file("/dev/urandom", twister::N); 57 | /* 58 | This reads characters from /dev/urandom and 59 | uses them to initialise the random number 60 | generator. 61 | 62 | The second argument is multiplied by 4 and 63 | then used as an upper bound on the number of 64 | characters to read. 65 | */ 66 | 67 | if($twister4->rangeint(1, 6) == 6) 68 | print "You've won -- congratulations!\n"; 69 | -------------------------------------------------------------------------------- /doc/internals/why-sub-works.txt: -------------------------------------------------------------------------------- 1 | This document explains why the function `sub' in the file 2 | mersenne_twister.php works. 3 | 4 | Suppose we want to calculate a - b, where a and b are integers and 5 | 6 | 0 <= a <= 2**31 - 1 7 | 0 <= b <= 2**31 - 1 8 | 9 | ("**" is the exponentiation operator; it binds more tightly than unary 10 | minus, so that, for example, -2**31 means -(2**31) and not (-2)**31.) 11 | 12 | Does `sub' do that? Yes, as the following reasoning shows. 13 | 14 | With a and b as above, let a1, a2, b1, b2 be integers such that 15 | 16 | a = a1 + a2, 17 | b = b1 + b2, 18 | 19 | where 20 | 21 | a1 = 0 or 2**31, 22 | b1 = 0 or 2**31, 23 | 0 <= a2 < 2**31, 24 | 0 <= b2 < 2**31. 25 | 26 | Let the notation , where x is 0 or 1 and y is an integer such that 27 | 0 <= y < 2**31, denote PHP's representation of a signed two's-complement 28 | integer on a 32-bit machine. For any such integer, x is the value of 29 | the MSB (i.e. the Most Significant Bit), and equals 1 if and only if 30 | the integer is negative. y is the number formed by taking the 31 least 31 | significant bits and treating them as an unsigned binary number. 32 | 33 | Now, it is clear that 34 | 35 | a - b = (a1 - b1) + (a2 - b2) 36 | 37 | It is also clear that any possible value of a2 - b2 can be represented 38 | in a PHP integer. 39 | 40 | Finally, identifying a and b here with $a and $b in the parameters of 41 | `sub', and considering the bit representation of the result of the 42 | expression (($a & MASK31) - ($b & MASK31)), which expression appears 43 | in the body of `sub', it can be seen that that the "top-level" xor in 44 | `sub', if it changes anything at all in the representation, does nothing 45 | but flip the MSB, and that the MSB is flipped if and only if a1 != b1. 46 | 47 | Now, it is clear that for any a1 and b1, we must have exactly one of 48 | the following 3 cases: 49 | 50 | a1 < b1 51 | a1 = b1 52 | a1 > b1 53 | 54 | Also, it is clear that for any a2 and b2, we must have exactly one of 55 | the following 2 cases: 56 | 57 | a2 < b2 58 | a2 >= b2 59 | 60 | Combining these 2 facts, we see that for any a1, b1, a2, b2, we have 61 | exactly one of the following 6 cases: 62 | 63 | 1) a1 < b1, a2 < b2 64 | 2) a1 < b1, a2 >= b2 65 | 3) a1 = b1, a2 < b2 66 | 4) a1 = b1, a2 >= b2 67 | 5) a1 > b1, a2 < b2 68 | 6) a1 > b1, a2 >= b2 69 | 70 | To show that `sub' works, we need to consider each case in turn. 71 | Before doing so, we will introduce some more notation. 72 | 73 | For any x, let r(x) = z, where 74 | 75 | 0 <= z < 2**32, 76 | z = x + n * 2**32, 77 | 78 | for some integer n. 79 | 80 | (Informally: r brings x inside the range of a 32-bit unsigned integer 81 | by adding or subtracting multiples of 2**32.) 82 | 83 | Let 84 | f(z1, z2, ) = 85 | if z1 = z2, 86 | <1 - x, y> otherwise. 87 | 88 | (Informally: f flips the MSB of its third argument if the first 2 89 | arguments of f are different.) 90 | 91 | Let u() = 2**31 * x + y. (Informally: u takes PHP's representation 92 | of, a signed integer and calculates what its value would be if it were 93 | an unsigned integer.) 94 | 95 | Let i(z) denote PHP's concrete representation, as a signed integer, 96 | of the integer z. 97 | 98 | Now, for each of the above 6 cases, we need to show that 99 | 100 | r(a - b) = u(f(a1, b1, i(a2 - b2))). (1) 101 | 102 | This is because `sub' computes a2 - b2, which is then fed into the 103 | top-level xor, which proceeds to compute f(a1, b1, i(a2 - b2)). 104 | 105 | In what follows, it will be useful to recall the fact that a signed 106 | 32-bit two's-complement integer is interpreted as 107 | 108 | 2**0 * x_0 + 2**1 * x_1 + ... + 109 | 2**29 * x_29 + 2**30 * x_30 + -2**31 * x_31, 110 | 111 | where x_i is the value of the bit at position i. Note that the 112 | coefficient of x_31 is negative, all the other coefficients being 113 | positive. 114 | 115 | We shall now treat each of the above cases in turn. 116 | 117 | Case 1: 118 | We are supposing: 119 | 120 | a1 < b1, a2 < b2 121 | 122 | So we have 123 | 124 | -2**31 < a2 - b2 < 0 125 | 126 | So 127 | 128 | a2 - b2 = -2**31 + y 129 | 130 | for some y such that 0 < y < 2**31. 131 | 132 | Therefore i(a2 - b2) = <1, y>. 133 | 134 | a1 - b1 = -2**31, 135 | so a - b = (a1 - b1) + (a2 - b2) = -2**32 + y, so r(a - b) = y. 136 | 137 | Since a1 != b1, the top-level xor will flip the MSB, so the function 138 | returns <0, y>, so (1) holds. 139 | 140 | Case 2: 141 | We are supposing: 142 | 143 | a1 < b1, a2 >= b2 144 | 145 | So we have: 146 | 147 | 0 <= a2 - b2 < 2**31 148 | a1 - b1 = -2**31 149 | 150 | a - b = (a1 - b1) + (a2 - b2) = -2**31 + a2 - b2 151 | 152 | Therefore, 153 | 154 | -2**31 <= a - b < 0 155 | 156 | So 157 | r(a - b) = 2**32 + a - b = 2**32 + (-2**31 + a2 - b2) = 2**31 + a2 - b2. 158 | 159 | We have 160 | 161 | i(a2 - b2) = <0, a2 - b2>. 162 | 163 | Since the top-level xor flips the MSB, we return <1, a2 - b2>, 164 | and u(<1, a2 - b2>) = r(a - b), so (1) holds. 165 | 166 | Case 3: 167 | We are supposing: 168 | 169 | a1 = b1, a2 < b2 170 | 171 | So we have: 172 | 173 | -2**31 < a2 - b2 < 0 174 | a - b = a2 - b2 175 | 176 | Clearly, 177 | 178 | a2 - b2 = -2**31 + y, 179 | 180 | for some y such that 0 < y < 2**31. So i(a2 - b2) = <1, y>. 181 | 182 | We have: 183 | 184 | r(a - b) = 2**32 + a2 - b2 = 2**31 + y 185 | 186 | Since a1 = b1, the MSB will not be flipped in <1, y>, 187 | and since r(a - b) = u(<1, y>), we will, by returning <1, y>, return the 188 | correct answer. 189 | 190 | Case 4: 191 | We are supposing: 192 | 193 | a1 = b1, a2 >= b2 194 | 195 | In this case, it is probably easy enough to see, 196 | without performing the formal reasoning below, that 197 | the code works. However, we shall proceed. 198 | 199 | We have: 200 | 201 | 0 <= a2 - b2 < 2**31 202 | a - b = a2 - b2 203 | r(a - b) = a2 - b2 204 | i(a2 - b2) = <0, a2 - b2>. 205 | r(a - b) = u(i(a2 - b2)) 206 | 207 | Since a1 = b1 the MSB is not changed, 208 | so the function returns <0, a2 - b2>, 209 | which is the desired answer. 210 | 211 | Case 5: 212 | We are supposing: 213 | 214 | a1 > b1, a2 < b2 215 | 216 | We have: 217 | 218 | -2**31 < a2 - b2 < 0 219 | 220 | Clearly, 221 | 222 | a2 - b2 = -2**31 + y, 223 | 224 | for some y such that 0 < y < 2**31. 225 | 226 | Therefore, i(a2 - b2) = <1, y>. 227 | 228 | a1 - b1 = 2**31, so a - b = y, so r(a - b) = y. 229 | Since a1 != b1, the MSB in <1, y> will be flipped, 230 | so we return <0, y>, which is the right answer, 231 | because r(a - b) = u(<0, y>). 232 | 233 | Case 6: 234 | We are supposing: 235 | 236 | a1 > b1, a2 >= b2 237 | 238 | We have: 239 | 240 | 0 <= a2 - b2 < 2**31 241 | i(a2 - b2) = <0, a2 - b2> 242 | a1 - b1 = 2**31 243 | a - b = 2**31 + a2 - b2 = r(a - b) 244 | 245 | Since a1 != b1, the MSB will be flipped, so we will 246 | return <1, a2 - b2>, which is the right answer, 247 | since r(a - b) = u(<1, a2 - b2>). 248 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | tests/phpunit/tests 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/mersenne_twister.php: -------------------------------------------------------------------------------- 1 | bits32 = PHP_INT_MAX == 2147483647; 69 | 70 | if(func_num_args() == 1) { 71 | $this->init_with_integer(func_get_arg(0)); 72 | } 73 | } 74 | 75 | function init_with_integer($integer_seed) { 76 | $integer_seed = force_32_bit_int($integer_seed); 77 | 78 | $mt = &$this->mt; 79 | $mti = &$this->mti; 80 | 81 | $mt = array_fill(0, N, 0); 82 | 83 | $mt[0] = $integer_seed; 84 | 85 | for($mti = 1; $mti < N; $mti++) { 86 | $mt[$mti] = add_2(mul(1812433253, 87 | ($mt[$mti - 1] ^ (($mt[$mti - 1] >> 30) & 3))), $mti); 88 | /* 89 | mt[mti] = 90 | (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 91 | */ 92 | } 93 | } 94 | 95 | function init_with_array(array $integer_array) { 96 | $integer_array = 97 | array_map(__NAMESPACE__ . "\\force_32_bit_int", $integer_array); 98 | 99 | $mt = &$this->mt; 100 | $mti = &$this->mti; 101 | 102 | $key_length = count($integer_array); 103 | 104 | $this->init_with_integer(19650218); 105 | $i=1; $j=0; 106 | $k = (N>$key_length ? N : $key_length); 107 | for (; $k; $k--) { 108 | $mt[$i] = add_3($mt[$i] ^ 109 | mul_by_1664525($mt[$i-1] ^ (($mt[$i-1] >> 30) & 3)), 110 | $integer_array[$j], $j); 111 | /* 112 | mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) 113 | + init_key[j] + j; 114 | */ 115 | $i++; $j++; 116 | if ($i>=N) { $mt[0] = $mt[N-1]; $i=1; } 117 | if ($j>=$key_length) $j=0; 118 | } 119 | for ($k=N-1; $k; $k--) { 120 | $mt[$i] = sub($mt[$i] ^ 121 | mul($mt[$i-1] ^ (($mt[$i-1] >> 30) & 3), 1566083941), $i); 122 | /* 123 | mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) 124 | - i; 125 | */ 126 | $i++; 127 | if ($i>=N) { $mt[0] = $mt[N-1]; $i=1; } 128 | } 129 | 130 | $mt[0] = (1 << 31); /* MSB is 1; assuring non-zero initial array */ 131 | } 132 | 133 | function init_with_string($string) { 134 | $remainder = strlen($string) % 4; 135 | 136 | if($remainder > 0) 137 | $string .= str_repeat("\0", 4 - $remainder); 138 | 139 | $integer_array = array_values(unpack("N*", $string)); 140 | 141 | $this->init_with_array($integer_array); 142 | } 143 | 144 | function init_with_files(array $filenames, $max_ints = -1) { 145 | $limit_applies = $max_ints !== -1; 146 | 147 | if($limit_applies) 148 | $limit = $max_ints * 4; # 32 bits is 4 characters 149 | 150 | $data = ""; 151 | 152 | foreach ($filenames as $filename) { 153 | $contents = 154 | file_get_contents($filename, FALSE, NULL, 0, 155 | $limit_applies? $limit - strlen($data): NULL); 156 | 157 | if($contents === FALSE) { 158 | throw new Exception("problem reading from $filename"); 159 | } else { 160 | $data .= $contents; 161 | 162 | if($limit_applies && strlen($data) == $limit) { 163 | break; 164 | } 165 | } 166 | } 167 | 168 | $this->init_with_string($data); 169 | } 170 | 171 | function init_with_file($filename, $max_ints = -1) { 172 | $this->init_with_files(array($filename), $max_ints); 173 | } 174 | 175 | function int32() { 176 | static $mag01 = array(0, MATRIX_A); 177 | 178 | $mt = &$this->mt; 179 | $mti = &$this->mti; 180 | 181 | if ($mti >= N) { /* generate N words all at once */ 182 | for ($kk=0;$kk> 1) & MASK31) ^ $mag01[$y & 1]; 185 | } 186 | for (;$kk> 1) & MASK31) ^ $mag01[$y & 1]; 190 | } 191 | $y = ($mt[N-1]&UPPER_MASK)|($mt[0]&LOWER_MASK); 192 | $mt[N-1] = $mt[M-1] ^ (($y >> 1) & MASK31) ^ $mag01[$y & 1]; 193 | 194 | $mti = 0; 195 | } 196 | 197 | $y = $mt[$mti++]; 198 | 199 | /* Tempering */ 200 | $y ^= ($y >> 11) & MASK21; 201 | $y ^= ($y << 7) & ((0x9d2c << 16) | 0x5680); 202 | $y ^= ($y << 15) & (0xefc6 << 16); 203 | $y ^= ($y >> 18) & MASK14; 204 | 205 | return $y; 206 | } 207 | 208 | function int31() { 209 | return $this->int32() & MASK31; 210 | } 211 | 212 | /* generates a random number on [0,1]-real-interval */ 213 | function real_closed() { 214 | return 215 | signed2unsigned($this->int32()) * (1.0 / 4294967295.0); 216 | } 217 | 218 | /* generates a random number on [0,1)-real-interval */ 219 | function real_halfopen() { 220 | return 221 | signed2unsigned($this->int32()) * (1.0 / 4294967296.0); 222 | } 223 | 224 | /* generates a random number on (0,1)-real-interval */ 225 | function real_open() { 226 | return (signed2unsigned($this->int32()) + .5) * 227 | (1.0 / 4294967296.0); 228 | } 229 | 230 | /* generates a random number on [0,1) with 53-bit resolution */ 231 | function real_halfopen2() { 232 | return 233 | ((($this->int32() & MASK27) * 67108864.0) + 234 | ($this->int32() & MASK26)) * 235 | (1.0 / 9007199254740992.0); 236 | } 237 | 238 | function rangeint($lower_bound, $upper_bound) { 239 | $lower_bound = intval($lower_bound); 240 | $upper_bound = intval($upper_bound); 241 | 242 | $this->check_bounds($lower_bound, $upper_bound); 243 | 244 | if($this->bits32) { 245 | $pow_2_32 = pow(2, 32); 246 | 247 | $size_of_range = $upper_bound - $lower_bound + 1; 248 | 249 | $remainder = fmod($pow_2_32, $size_of_range); 250 | 251 | if($remainder == 0) { 252 | return $lower_bound + 253 | ($this->int32() & unsigned2signed($size_of_range - 1)); 254 | } else { 255 | $start_of_partial_range = $pow_2_32 - $remainder; 256 | $start_as_int = unsigned2signed($start_of_partial_range); 257 | do { 258 | $rand = $this->int32(); 259 | } while($rand >= $start_as_int && $rand < 0); 260 | 261 | $result = $lower_bound + 262 | fmod(signed2unsigned($rand), $size_of_range); 263 | 264 | return intval($result); 265 | } 266 | } else { 267 | if($lower_bound == -PHP_INT_MAX - 1 && $upper_bound == PHP_INT_MAX) { 268 | return ($this->int32() << 32) | $this->int32(); 269 | } else { 270 | $pow_2_32 = 1 << 32; 271 | 272 | $size_of_range = $upper_bound - $lower_bound + 1; 273 | 274 | if($size_of_range > $pow_2_32) { 275 | $size_of_range >>= 32; 276 | $shift = 32; 277 | $low_bits = $this->int32(); 278 | } else { 279 | $shift = 0; 280 | $low_bits = 0; 281 | } 282 | 283 | $remainder = $pow_2_32 % $size_of_range; 284 | 285 | if($remainder == 0) { 286 | $high_bits = $this->int32() & ($size_of_range - 1); 287 | } else { 288 | $start_of_partial_range = $pow_2_32 - $remainder; 289 | do { 290 | $rand = $this->int32(); 291 | } while($rand >= $start_of_partial_range); 292 | 293 | $high_bits = $rand % $size_of_range; 294 | } 295 | 296 | return $lower_bound + (($high_bits << $shift) | $low_bits); 297 | } 298 | } 299 | } 300 | 301 | /* 302 | in each of the next 3 functions, we loop until we have a number that 303 | meets the function's post-condition. this may be more work than 304 | is really necessary, but i am concerned about rounding errors. 305 | 306 | why no rangereal_closed? because, due to the aforementioned 307 | rounding errors, i am unable to guarantee that $upper_bound 308 | would be a possible return value of such a function. 309 | */ 310 | 311 | function rangereal_open($lower_bound, $upper_bound) { 312 | $this->check_bounds($lower_bound, $upper_bound); 313 | 314 | do { 315 | $rand = $lower_bound + 316 | $this->real_open() * ($upper_bound - $lower_bound); 317 | } while($rand <= $lower_bound || $rand >= $upper_bound); 318 | 319 | return $rand; 320 | } 321 | 322 | function rangereal_halfopen($lower_bound, $upper_bound) { 323 | $this->check_bounds($lower_bound, $upper_bound); 324 | 325 | do { 326 | $rand = $lower_bound + 327 | $this->real_halfopen() * ($upper_bound - $lower_bound); 328 | } while($rand >= $upper_bound); 329 | /* 330 | $rand cannot go any lower than $lower_bound, because 331 | $this->real_halfopen() cannot go any lower than 0 332 | */ 333 | 334 | return $rand; 335 | } 336 | 337 | function rangereal_halfopen2($lower_bound, $upper_bound) { 338 | $this->check_bounds($lower_bound, $upper_bound); 339 | 340 | do { 341 | $rand = $lower_bound + 342 | $this->real_halfopen2() * ($upper_bound - $lower_bound); 343 | } while($rand >= $upper_bound); 344 | 345 | return $rand; 346 | } 347 | 348 | function test() { 349 | ob_start(); 350 | $this->exercise(); 351 | $output = ob_get_clean(); 352 | 353 | if(md5($output) !== "cb33e6acc162cbe20f7fcac26adddd02") { 354 | print "Test failed.\n"; 355 | } 356 | } 357 | 358 | private function check_bounds($lower_bound, $upper_bound) { 359 | if($lower_bound > $upper_bound) { 360 | $message = 361 | 'lower bound exceeds upper bound: ' . 362 | "$lower_bound > $upper_bound"; 363 | throw new Exception($message); 364 | } 365 | } 366 | 367 | private function exercise() { 368 | /* 369 | we keep the names "genrand_int32" and "genrand_real2" because 370 | we want the output of this function to be identical to that 371 | produced by mtTest.c. (The file mtTest.c is part of the archive 372 | mt19937ar.sep.tgz, mentioned above.) 373 | */ 374 | 375 | $this->init_with_array(array(0x123, 0x234, 0x345, 0x456)); 376 | printf("1000 outputs of genrand_int32()\n"); 377 | for ($i=0; $i<1000; $i++) { 378 | printf("%10lu ", $this->int32()); 379 | if ($i%5==4) printf("\n"); 380 | } 381 | printf("\n1000 outputs of genrand_real2()\n"); 382 | for ($i=0; $i<1000; $i++) { 383 | printf("%10.8f ", $this->real_halfopen()); 384 | if ($i%5==4) printf("\n"); 385 | } 386 | } 387 | } 388 | 389 | function signed2unsigned($signed_integer) { 390 | ## assert(is_integer($signed_integer)); 391 | ## assert(($signed_integer & ~MASK32) === 0); 392 | 393 | return $signed_integer >= 0? $signed_integer: 394 | TWO_TO_THE_32 + $signed_integer; 395 | } 396 | 397 | function unsigned2signed($unsigned_integer) { 398 | ## assert($unsigned_integer >= 0); 399 | ## assert($unsigned_integer < pow(2, 32)); 400 | ## assert(floor($unsigned_integer) === floatval($unsigned_integer)); 401 | 402 | return intval($unsigned_integer < TWO_TO_THE_31? $unsigned_integer: 403 | $unsigned_integer - TWO_TO_THE_32); 404 | } 405 | 406 | function force_32_bit_int($x) { 407 | /* 408 | it would be un-PHP-like to require is_integer($x), 409 | so we have to handle cases like this: 410 | 411 | $x === pow(2, 31) 412 | $x === strval(pow(2, 31)) 413 | 414 | we are also opting to do something sensible (rather than dying) 415 | if the seed is outside the range of a 32-bit unsigned integer. 416 | */ 417 | 418 | if(is_integer($x)) { 419 | /* 420 | we mask in case we are on a 64-bit machine and at least one 421 | bit is set between position 32 and position 63. 422 | */ 423 | return $x & MASK32; 424 | } else { 425 | $x = floatval($x); 426 | 427 | $x = $x < 0? ceil($x): floor($x); 428 | 429 | $x = fmod($x, TWO_TO_THE_32); 430 | 431 | if($x < 0) 432 | $x += TWO_TO_THE_32; 433 | 434 | return unsigned2signed($x); 435 | } 436 | } 437 | 438 | /* 439 | takes 2 integers, treats them as unsigned 32-bit integers, 440 | and adds them. 441 | 442 | it works by splitting each integer into 443 | 2 "half-integers", then adding the high and low half-integers 444 | separately. 445 | 446 | a slight complication is that the sum of the low half-integers 447 | may not fit into 16 bits; any "overspill" is added to the sum 448 | of the high half-integers. 449 | */ 450 | function add_2($n1, $n2) { 451 | $x = ($n1 & 0xffff) + ($n2 & 0xffff); 452 | 453 | return 454 | (((($n1 >> 16) & 0xffff) + 455 | (($n2 >> 16) & 0xffff) + 456 | ($x >> 16)) << 16) | ($x & 0xffff); 457 | } 458 | 459 | # takes 2 integers, treats them as unsigned 32-bit integers, 460 | # and adds them. 461 | # 462 | # for how it works, see the comment for add_2. 463 | # 464 | function add_3($n1, $n2, $n3) { 465 | $x = ($n1 & 0xffff) + ($n2 & 0xffff) + ($n3 & 0xffff); 466 | 467 | return 468 | (((($n1 >> 16) & 0xffff) + 469 | (($n2 >> 16) & 0xffff) + 470 | (($n3 >> 16) & 0xffff) + 471 | ($x >> 16)) << 16) | ($x & 0xffff); 472 | } 473 | 474 | # takes 2 integers, treats them as unsigned 32-bit integers, 475 | # and subtracts the second from the first. 476 | # 477 | # the explanation of why this works is too long to be 478 | # included here, so it has been moved into the file why-sub-works.txt. 479 | # 480 | function sub($a, $b) { 481 | return (($a & MASK31) - ($b & MASK31)) ^ 482 | (($a ^ $b) & 0x80000000); 483 | } 484 | 485 | function test_sub() { 486 | for($i = 0; $i < 5000; $i++) { 487 | $n1 = get_random_32bit_int(); 488 | $n2 = get_random_32bit_int(); 489 | $result = sub($n1, $n2); 490 | $result_from_bc = do_bc_op("bcsub", array($n1, $n2)); 491 | if($result != $result_from_bc) { 492 | printf("problem in %s: %s %s %s %s\n", 493 | __FUNCTION__, $n1, $n2, $result, $result_from_bc); 494 | } 495 | } 496 | } 497 | 498 | function mul($a, $b) { 499 | /* 500 | a and b, considered as unsigned integers, can be expressed as follows: 501 | 502 | a = 2**16 * a1 + a2, 503 | 504 | b = 2**16 * b1 + b2, 505 | 506 | where 507 | 508 | 0 <= a2 < 2**16, 509 | 0 <= b2 < 2**16. 510 | 511 | given those 2 equations, what this function essentially does is to 512 | use the following identity: 513 | 514 | a * b = 2**32 * a1 * b1 + 2**16 * a1 * b2 + 2**16 * b1 * a2 + a2 * b2 515 | 516 | note that the first term, i.e. 2**32 * a1 * b1, is unnecessary here, 517 | so we don't compute it. 518 | 519 | we could make the following code clearer by using intermediate 520 | variables, but that would probably hurt performance. 521 | */ 522 | 523 | return 524 | unsigned2signed( 525 | fmod( 526 | TWO_TO_THE_16 * 527 | /* 528 | the next line of code calculates a1 * b2, 529 | the line after that calculates b1 * a2, 530 | and the line after that calculates a2 * b2. 531 | */ 532 | ((($a >> 16) & 0xffff) * ($b & 0xffff) + 533 | (($b >> 16) & 0xffff) * ($a & 0xffff)) + 534 | ($a & 0xffff) * ($b & 0xffff), 535 | 536 | TWO_TO_THE_32)); 537 | } 538 | 539 | /* 540 | mul_by_1664525($x) should be more efficient than mul(1664525, $x). 541 | */ 542 | function mul_by_1664525($n) { 543 | return unsigned2signed(fmod(1664525 * ($n >= 0? 544 | $n: (TWO_TO_THE_32 + $n)), TWO_TO_THE_32)); 545 | } 546 | 547 | function do_bc_op($bc_op, array $numbers) { 548 | $modulus = pow(2, 32); 549 | 550 | $result = 551 | call_user_func_array($bc_op, 552 | array_map(__NAMESPACE__ . "\\signed2unsigned", $numbers)); 553 | 554 | $result = bcmod($result, $modulus); 555 | 556 | return unsigned2signed(bccomp($result, 0) < 0? 557 | bcadd($result, $modulus): $result); 558 | } 559 | 560 | function get_random_32bit_int() { 561 | return rand(0, 0xffff) | (rand(0, 0xffff) << 16); 562 | } 563 | -------------------------------------------------------------------------------- /tests/checksums: -------------------------------------------------------------------------------- 1 | ba79d97d127330ad12538395723d3c6bdabacd010bb8b845b900f2e5e3de0ad199b41d21e9fbe7a9c01f5a88a827c9da2dac3ba09da64648e63ad4eef069e48e composer-setup.php 2 | -------------------------------------------------------------------------------- /tests/phpunit/tests/TwisterTest.php: -------------------------------------------------------------------------------- 1 | twister = new twister(42); 10 | } 11 | 12 | /** @dataProvider provideMethodsThatTakeBounds */ 13 | public function testEmptyBoundsDetected($method_name) { 14 | #> Given 15 | 16 | $low_num = 0; 17 | $high_num = 100; 18 | 19 | $exception = NULL; 20 | 21 | #> When 22 | 23 | try { 24 | $this->twister->$method_name($high_num, $low_num); 25 | } catch(Exception $exception) {} 26 | 27 | #> Then 28 | 29 | $this->assertNotNull($exception); 30 | } 31 | 32 | public function provideMethodsThatTakeBounds() { 33 | return array( 34 | array('rangeint'), 35 | array('rangereal_open'), 36 | array('rangereal_halfopen'), 37 | array('rangereal_halfopen2'), 38 | ); 39 | } 40 | 41 | public function testFailureOnNonExistentInitFile() { 42 | #> Given 43 | 44 | $twister = new twister; 45 | $exception = NULL; 46 | 47 | #> When 48 | 49 | try { 50 | $twister->init_with_file($this->getNonExistentFile()); 51 | } catch(Exception $exception) {} 52 | 53 | #> Then 54 | 55 | $this->assertNotNull($exception); 56 | } 57 | 58 | /* 59 | This tests for a bug which was present at one time. 60 | */ 61 | public function testRangeIntWorksOnWidest64BitRange() { 62 | if(PHP_INT_SIZE !== 8) { 63 | $this->markTestSkipped('not a 64-bit system'); 64 | } 65 | 66 | #> Given 67 | 68 | $twister = new twister(42); 69 | /*< 70 | The Mersenne Twister is deterministic, so we can initialise it 71 | with any value that makes the assertion below true. 72 | */ 73 | 74 | #> When 75 | 76 | $rand = $twister->rangeint(-PHP_INT_MAX - 1, PHP_INT_MAX); 77 | 78 | #> Then 79 | 80 | $this->assertNotEquals($rand, 0); 81 | } 82 | 83 | private function getNonExistentFile() { 84 | return __DIR__ . '/non-existent'; 85 | } 86 | 87 | private $twister; 88 | } 89 | -------------------------------------------------------------------------------- /tests/test-php-versions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script runs our tests in various PHP minor releases. 4 | # To run the script, Docker is required. 5 | 6 | main() { 7 | local versions 8 | 9 | cd "$(dirname "$0")"/.. 10 | 11 | versions=' 12 | 7.3.33 13 | 7.4.33 14 | 8.0.28 15 | 8.1.17 16 | 8.2.4 17 | ' 18 | 19 | base_docker_tag=tmp-8049:tmp 20 | test_docker_tag=tmp-14933 21 | 22 | generate_dockerfile_for_base_image "$v" | 23 | docker build --quiet --file - --tag "$base_docker_tag" . 24 | 25 | for v in $versions; do 26 | echo Start of test with PHP version $v 27 | generate_dockerfile_for_test_image "$base_docker_tag" "$v" | 28 | docker build --quiet --file - --tag "$test_docker_tag" . 29 | docker run --rm "$test_docker_tag" vendor/bin/phpunit -c phpunit.xml 30 | echo End of test with PHP version $v 31 | docker image rm "$test_docker_tag" 32 | echo 33 | done 34 | 35 | docker image rm "$base_docker_tag" 36 | } 37 | 38 | generate_dockerfile_for_base_image() { 39 | cat <