1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the program and library */ 4 /* SCIP --- Solving Constraint Integer Programs */ 5 /* */ 6 /* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */ 7 /* */ 8 /* Licensed under the Apache License, Version 2.0 (the "License"); */ 9 /* you may not use this file except in compliance with the License. */ 10 /* You may obtain a copy of the License at */ 11 /* */ 12 /* http://www.apache.org/licenses/LICENSE-2.0 */ 13 /* */ 14 /* Unless required by applicable law or agreed to in writing, software */ 15 /* distributed under the License is distributed on an "AS IS" BASIS, */ 16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ 17 /* See the License for the specific language governing permissions and */ 18 /* limitations under the License. */ 19 /* */ 20 /* You should have received a copy of the Apache-2.0 license */ 21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */ 22 /* */ 23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 24 25 /**@file disp.c 26 * @ingroup OTHER_CFILES 27 * @brief methods and datastructures for displaying runtime statistics 28 * @author Tobias Achterberg 29 * @author Timo Berthold 30 */ 31 32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 33 34 #include <stdio.h> 35 #include <assert.h> 36 #include <string.h> 37 38 #include "scip/def.h" 39 #include "blockmemshell/memory.h" 40 #include "scip/set.h" 41 #include "scip/stat.h" 42 #include "scip/scip.h" 43 #include "scip/disp.h" 44 #include "scip/pub_message.h" 45 #include "scip/pub_misc.h" 46 #include "scip/syncstore.h" 47 #include "scip/struct_disp.h" 48 49 50 51 /* 52 * display column methods 53 */ 54 55 /** parameter change information method to autoselect display columns again */ 56 SCIP_DECL_PARAMCHGD(SCIPparamChgdDispActive) 57 { /*lint --e{715}*/ 58 /* automatically select the now active display columns */ 59 SCIP_CALL( SCIPautoselectDisps(scip) ); 60 61 return SCIP_OKAY; 62 } 63 64 /** copies the given display to a new scip */ 65 SCIP_RETCODE SCIPdispCopyInclude( 66 SCIP_DISP* disp, /**< display column */ 67 SCIP_SET* set /**< SCIP_SET of SCIP to copy to */ 68 ) 69 { 70 assert(disp != NULL); 71 assert(set != NULL); 72 assert(set->scip != NULL); 73 74 if( disp->dispcopy != NULL ) 75 { 76 SCIPsetDebugMsg(set, "including display column %s in subscip %p\n", SCIPdispGetName(disp), (void*)set->scip); 77 SCIP_CALL( disp->dispcopy(set->scip, disp) ); 78 } 79 return SCIP_OKAY; 80 } 81 82 /** internal method for creating a display column */ 83 static 84 SCIP_RETCODE doDispCreate( 85 SCIP_DISP** disp, /**< pointer to store display column */ 86 SCIP_SET* set, /**< global SCIP settings */ 87 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 88 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */ 89 const char* name, /**< name of display column */ 90 const char* desc, /**< description of display column */ 91 const char* header, /**< head line of display column */ 92 SCIP_DISPSTATUS dispstatus, /**< display activation status of display column */ 93 SCIP_DECL_DISPCOPY ((*dispcopy)), /**< copy method of display column or NULL if you don't want to copy your plugin into sub-SCIPs */ 94 SCIP_DECL_DISPFREE ((*dispfree)), /**< destructor of display column */ 95 SCIP_DECL_DISPINIT ((*dispinit)), /**< initialize display column */ 96 SCIP_DECL_DISPEXIT ((*dispexit)), /**< deinitialize display column */ 97 SCIP_DECL_DISPINITSOL ((*dispinitsol)), /**< solving process initialization method of display column */ 98 SCIP_DECL_DISPEXITSOL ((*dispexitsol)), /**< solving process deinitialization method of display column */ 99 SCIP_DECL_DISPOUTPUT ((*dispoutput)), /**< output method */ 100 SCIP_DISPDATA* dispdata, /**< display column data */ 101 int width, /**< width of display column (no. of chars used) */ 102 int priority, /**< priority of display column */ 103 int position, /**< relative position of display column */ 104 SCIP_Bool stripline /**< should the column be separated with a line from its right neighbor? */ 105 ) 106 { 107 char paramname[SCIP_MAXSTRLEN]; 108 char paramdesc[SCIP_MAXSTRLEN]; 109 110 assert(disp != NULL); 111 assert(name != NULL); 112 assert(desc != NULL); 113 assert(header != NULL); 114 assert(dispoutput != NULL); 115 assert(width >= 0); 116 117 SCIP_ALLOC( BMSallocMemory(disp) ); 118 BMSclearMemory(*disp); 119 120 SCIP_ALLOC( BMSduplicateMemoryArray(&(*disp)->name, name, strlen(name)+1) ); 121 SCIP_ALLOC( BMSduplicateMemoryArray(&(*disp)->desc, desc, strlen(desc)+1) ); 122 SCIP_ALLOC( BMSduplicateMemoryArray(&(*disp)->header, header, strlen(header)+1) ); 123 (*disp)->dispstatus = dispstatus; 124 (*disp)->dispcopy = dispcopy; 125 (*disp)->dispfree = dispfree; 126 (*disp)->dispinit = dispinit; 127 (*disp)->dispexit = dispexit; 128 (*disp)->dispinitsol = dispinitsol; 129 (*disp)->dispexitsol = dispexitsol; 130 (*disp)->dispoutput = dispoutput; 131 (*disp)->dispdata = dispdata; 132 (*disp)->width = width; 133 (*disp)->priority = priority; 134 (*disp)->position = position; 135 (*disp)->stripline = stripline; 136 (*disp)->initialized = FALSE; 137 (*disp)->active = (dispstatus == SCIP_DISPSTATUS_ON); 138 (*disp)->mode = SCIP_DISPMODE_DEFAULT; 139 140 /* add parameters */ 141 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "display/%s/active", name); 142 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "display activation status of display column <%s> (0: off, 1: auto, 2:on)", name); 143 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc, 144 (int*)(&(*disp)->dispstatus), FALSE, (int)dispstatus, 0, 2, SCIPparamChgdDispActive, NULL) ); 145 146 return SCIP_OKAY; 147 } 148 149 /** creates a display column */ 150 SCIP_RETCODE SCIPdispCreate( 151 SCIP_DISP** disp, /**< pointer to store display column */ 152 SCIP_SET* set, /**< global SCIP settings */ 153 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 154 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */ 155 const char* name, /**< name of display column */ 156 const char* desc, /**< description of display column */ 157 const char* header, /**< head line of display column */ 158 SCIP_DISPSTATUS dispstatus, /**< display activation status of display column */ 159 SCIP_DECL_DISPCOPY ((*dispcopy)), /**< copy method of display column or NULL if you don't want to copy your plugin into sub-SCIPs */ 160 SCIP_DECL_DISPFREE ((*dispfree)), /**< destructor of display column */ 161 SCIP_DECL_DISPINIT ((*dispinit)), /**< initialize display column */ 162 SCIP_DECL_DISPEXIT ((*dispexit)), /**< deinitialize display column */ 163 SCIP_DECL_DISPINITSOL ((*dispinitsol)), /**< solving process initialization method of display column */ 164 SCIP_DECL_DISPEXITSOL ((*dispexitsol)), /**< solving process deinitialization method of display column */ 165 SCIP_DECL_DISPOUTPUT ((*dispoutput)), /**< output method */ 166 SCIP_DISPDATA* dispdata, /**< display column data */ 167 int width, /**< width of display column (no. of chars used) */ 168 int priority, /**< priority of display column */ 169 int position, /**< relative position of display column */ 170 SCIP_Bool stripline /**< should the column be separated with a line from its right neighbor? */ 171 ) 172 { 173 assert(disp != NULL); 174 assert(name != NULL); 175 assert(desc != NULL); 176 assert(header != NULL); 177 assert(dispoutput != NULL); 178 assert(width >= 0); 179 180 SCIP_CALL_FINALLY( doDispCreate(disp, set, messagehdlr, blkmem, name, desc, header, dispstatus, dispcopy, 181 dispfree, dispinit, dispexit, dispinitsol, dispexitsol, dispoutput, dispdata, width, priority, position, 182 stripline), (void) SCIPdispFree(disp, set) ); 183 184 return SCIP_OKAY; 185 } 186 187 /** frees memory of display column */ 188 SCIP_RETCODE SCIPdispFree( 189 SCIP_DISP** disp, /**< pointer to display column data structure */ 190 SCIP_SET* set /**< global SCIP settings */ 191 ) 192 { 193 assert(disp != NULL); 194 if( *disp == NULL ) 195 return SCIP_OKAY; 196 assert(!(*disp)->initialized); 197 assert(set != NULL); 198 199 /* call destructor of display column */ 200 if( (*disp)->dispfree != NULL ) 201 { 202 SCIP_CALL( (*disp)->dispfree(set->scip, *disp) ); 203 } 204 205 BMSfreeMemoryArrayNull(&(*disp)->name); 206 BMSfreeMemoryArrayNull(&(*disp)->desc); 207 BMSfreeMemoryArrayNull(&(*disp)->header); 208 BMSfreeMemory(disp); 209 210 return SCIP_OKAY; 211 } 212 213 /** initializes display column */ 214 SCIP_RETCODE SCIPdispInit( 215 SCIP_DISP* disp, /**< display column */ 216 SCIP_SET* set /**< global SCIP settings */ 217 ) 218 { 219 assert(disp != NULL); 220 assert(set != NULL); 221 222 if( disp->initialized ) 223 { 224 SCIPerrorMessage("display column <%s> already initialized\n", disp->name); 225 return SCIP_INVALIDCALL; 226 } 227 228 if( disp->dispinit != NULL ) 229 { 230 SCIP_CALL( disp->dispinit(set->scip, disp) ); 231 } 232 disp->initialized = TRUE; 233 234 return SCIP_OKAY; 235 } 236 237 /** deinitializes display column */ 238 SCIP_RETCODE SCIPdispExit( 239 SCIP_DISP* disp, /**< display column */ 240 SCIP_SET* set /**< global SCIP settings */ 241 ) 242 { 243 assert(disp != NULL); 244 assert(set != NULL); 245 246 if( !disp->initialized ) 247 { 248 SCIPerrorMessage("display column <%s> not initialized\n", disp->name); 249 return SCIP_INVALIDCALL; 250 } 251 252 if( disp->dispexit != NULL ) 253 { 254 SCIP_CALL( disp->dispexit(set->scip, disp) ); 255 } 256 disp->initialized = FALSE; 257 258 return SCIP_OKAY; 259 } 260 261 /** informs display column that the branch and bound process is being started */ 262 SCIP_RETCODE SCIPdispInitsol( 263 SCIP_DISP* disp, /**< display column */ 264 SCIP_SET* set /**< global SCIP settings */ 265 ) 266 { 267 assert(disp != NULL); 268 assert(set != NULL); 269 270 /* call solving process initialization method of display column */ 271 if( disp->dispinitsol != NULL ) 272 { 273 SCIP_CALL( disp->dispinitsol(set->scip, disp) ); 274 } 275 276 return SCIP_OKAY; 277 } 278 279 /** informs display column that the branch and bound process data is being freed */ 280 SCIP_RETCODE SCIPdispExitsol( 281 SCIP_DISP* disp, /**< display column */ 282 SCIP_SET* set /**< global SCIP settings */ 283 ) 284 { 285 assert(disp != NULL); 286 assert(set != NULL); 287 288 /* call solving process deinitialization method of display column */ 289 if( disp->dispexitsol != NULL ) 290 { 291 SCIP_CALL( disp->dispexitsol(set->scip, disp) ); 292 } 293 294 return SCIP_OKAY; 295 } 296 297 /** output display column to screen */ 298 SCIP_RETCODE SCIPdispOutput( 299 SCIP_DISP* disp, /**< display column */ 300 SCIP_SET* set, /**< global SCIP settings */ 301 FILE* file /**< output file (or NULL for standard output) */ 302 ) 303 { 304 assert(disp != NULL); 305 assert(disp->dispoutput != NULL); 306 assert(set != NULL); 307 308 SCIP_CALL( disp->dispoutput(set->scip, disp, file) ); 309 310 return SCIP_OKAY; 311 } 312 313 /** gets user data of display column */ 314 SCIP_DISPDATA* SCIPdispGetData( 315 SCIP_DISP* disp /**< display column */ 316 ) 317 { 318 assert(disp != NULL); 319 320 return disp->dispdata; 321 } 322 323 /** sets user data of display column; user has to free old data in advance! */ 324 void SCIPdispSetData( 325 SCIP_DISP* disp, /**< display column */ 326 SCIP_DISPDATA* dispdata /**< new display column user data */ 327 ) 328 { 329 assert(disp != NULL); 330 331 disp->dispdata = dispdata; 332 } 333 334 /** gets name of display column */ 335 const char* SCIPdispGetName( 336 SCIP_DISP* disp /**< display column */ 337 ) 338 { 339 assert(disp != NULL); 340 341 return disp->name; 342 } 343 344 /** gets description of display column */ 345 const char* SCIPdispGetDesc( 346 SCIP_DISP* disp /**< display column */ 347 ) 348 { 349 assert(disp != NULL); 350 351 return disp->desc; 352 } 353 354 /** gets head line of display column */ 355 const char* SCIPdispGetHeader( 356 SCIP_DISP* disp /**< display column */ 357 ) 358 { 359 assert(disp != NULL); 360 361 return disp->header; 362 } 363 364 /** gets width of display column */ 365 int SCIPdispGetWidth( 366 SCIP_DISP* disp /**< display column */ 367 ) 368 { 369 assert(disp != NULL); 370 371 return disp->width; 372 } 373 374 /** gets priority of display column */ 375 int SCIPdispGetPriority( 376 SCIP_DISP* disp /**< display column */ 377 ) 378 { 379 assert(disp != NULL); 380 381 return disp->priority; 382 } 383 384 /** gets position of display column */ 385 int SCIPdispGetPosition( 386 SCIP_DISP* disp /**< display column */ 387 ) 388 { 389 assert(disp != NULL); 390 391 return disp->position; 392 } 393 394 /** gets status of display column */ 395 SCIP_DISPSTATUS SCIPdispGetStatus( 396 SCIP_DISP* disp /**< display column */ 397 ) 398 { 399 assert(disp != NULL); 400 401 return disp->dispstatus; 402 } 403 404 /** is display column initialized? */ 405 SCIP_Bool SCIPdispIsInitialized( 406 SCIP_DISP* disp /**< display column */ 407 ) 408 { 409 assert(disp != NULL); 410 411 return disp->initialized; 412 } 413 414 /** prints one line of output with the active display columns */ 415 SCIP_RETCODE SCIPdispPrintLine( 416 SCIP_SET* set, /**< global SCIP settings */ 417 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 418 SCIP_STAT* stat, /**< problem statistics data */ 419 FILE* file, /**< output file (or NULL for standard output) */ 420 SCIP_Bool forcedisplay, /**< should the line be printed without regarding frequency? */ 421 SCIP_Bool endline /**< should the line be terminated with a newline symbol? */ 422 ) 423 { 424 assert(set != NULL); 425 assert(set->disp_freq >= -1); 426 assert(set->disp_headerfreq >= -1); 427 assert(stat != NULL); 428 429 if( (SCIP_VERBLEVEL)set->disp_verblevel < SCIP_VERBLEVEL_NORMAL || set->disp_freq == -1 ) 430 return SCIP_OKAY; 431 432 if( forcedisplay 433 || (stat->nnodes != stat->lastdispnode 434 && set->disp_freq > 0 435 && (stat->nnodes % set->disp_freq == 0 || stat->nnodes == 1)) ) 436 { 437 int i; 438 int j; 439 SCIP_Bool stripline; 440 441 /* display header line */ 442 if( (set->disp_headerfreq == 0 && stat->ndisplines == 0) 443 || (set->disp_headerfreq > 0 && stat->ndisplines % set->disp_headerfreq == 0) ) 444 { 445 int fillspace; 446 447 stripline = FALSE; 448 for( i = 0; i < set->ndisps; ++i ) 449 { 450 assert(set->disps[i] != NULL); 451 if( set->disps[i]->active ) 452 { 453 if( stripline ) 454 SCIPmessageFPrintInfo(messagehdlr, file, "|"); 455 fillspace = set->disps[i]->width - (int)strlen(set->disps[i]->header); 456 for( j = 0; j < (fillspace)/2; ++j ) 457 SCIPmessageFPrintInfo(messagehdlr, file, " "); 458 SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)set->disps[i]->header); 459 for( j = 0; j < (fillspace+1)/2; ++j ) 460 SCIPmessageFPrintInfo(messagehdlr, file, " "); 461 stripline = set->disps[i]->stripline; 462 } 463 } 464 SCIPmessageFPrintInfo(messagehdlr, file, "\n"); 465 } 466 467 /* display node information line */ 468 stripline = FALSE; 469 for( i = 0; i < set->ndisps; ++i ) 470 { 471 assert(set->disps[i] != NULL); 472 if( set->disps[i]->active ) 473 { 474 if( stripline ) 475 SCIPmessageFPrintInfo(messagehdlr, file, "|"); 476 SCIP_CALL( SCIPdispOutput(set->disps[i], set, file) ); 477 stripline = set->disps[i]->stripline; 478 } 479 } 480 if( endline ) 481 { 482 SCIPmessageFPrintInfo(messagehdlr, file, "\n"); 483 } 484 fflush(stdout); 485 486 stat->lastdispnode = stat->nnodes; 487 stat->ndisplines++; 488 } 489 490 return SCIP_OKAY; 491 } 492 493 /** comparison method for display columns */ 494 static 495 SCIP_DECL_SORTPTRCOMP(dispComp) 496 { /*lint --e{715}*/ 497 return ((SCIP_DISP*)elem2)->priority - ((SCIP_DISP*)elem1)->priority; 498 } 499 500 /** activates all display lines fitting in the display w.r. to priority */ 501 SCIP_RETCODE SCIPdispAutoActivate( 502 SCIP_SET* set /**< global SCIP settings */ 503 ) 504 { 505 SCIP_DISP** disps; 506 SCIP_SYNCSTORE* syncstore; 507 SCIP_DISPMODE mode; 508 int totalwidth; 509 int width; 510 int i; 511 512 assert(set != NULL); 513 514 syncstore = SCIPgetSyncstore(set->scip); 515 assert(syncstore != NULL); 516 517 /* sort display columns w.r. to their priority */ 518 SCIP_ALLOC( BMSduplicateMemoryArray(&disps, set->disps, set->ndisps) ); 519 SCIPsortPtr((void**)disps, dispComp, set->ndisps); 520 521 totalwidth = 0; 522 523 if( SCIPsyncstoreIsInitialized(syncstore) ) 524 mode = SCIP_DISPMODE_CONCURRENT; 525 else 526 mode = SCIP_DISPMODE_DEFAULT; 527 528 /* first activate all columns with display status ON */ 529 for( i = 0; i < set->ndisps; ++i ) 530 { 531 width = disps[i]->width; 532 if( disps[i]->stripline ) 533 width++; 534 if( disps[i]->dispstatus == SCIP_DISPSTATUS_ON && (disps[i]->mode & mode) ) 535 { 536 disps[i]->active = TRUE; 537 totalwidth += width; 538 } 539 else 540 disps[i]->active = FALSE; 541 } 542 543 /* beginning with highest priority display column, activate AUTO columns as long as it fits into display width */ 544 for( i = 0; i < set->ndisps; ++i ) 545 { 546 if( disps[i]->dispstatus == SCIP_DISPSTATUS_AUTO ) 547 { 548 assert(!disps[i]->active); 549 550 width = disps[i]->width; 551 if( disps[i]->stripline ) 552 width++; 553 if( totalwidth + width <= set->disp_width && (disps[i]->mode & mode) ) 554 { 555 disps[i]->active = TRUE; 556 totalwidth += width; 557 } 558 } 559 } 560 561 /* free temporary memory */ 562 BMSfreeMemoryArray(&disps); 563 564 return SCIP_OKAY; 565 } 566 567 /** changes the display column mode */ 568 void SCIPdispChgMode( 569 SCIP_DISP* disp, /**< display column */ 570 SCIP_DISPMODE mode /**< the display column mode */ 571 ) 572 { 573 disp->mode = mode; 574 } 575 576 static 577 const char decpowerchar[] = {' ', 'k', 'M', 'G', 'T', 'P', 'E'}; 578 #define MAXDECPOWER 6 579 580 /** displays a long integer in decimal form fitting in a given width */ 581 void SCIPdispLongint( 582 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 583 FILE* file, /**< output stream */ 584 SCIP_Longint val, /**< value to display */ 585 int width /**< width to fit into */ 586 ) 587 { 588 assert(width >= 1); 589 590 if( width == 1 ) 591 { 592 if( val < 0 ) 593 SCIPmessageFPrintInfo(messagehdlr, file, "-"); 594 else if( val < 10 ) 595 SCIPmessageFPrintInfo(messagehdlr, file, "%" SCIP_LONGINT_FORMAT, val); 596 else 597 SCIPmessageFPrintInfo(messagehdlr, file, "+"); 598 } 599 else 600 { 601 char format[SCIP_MAXSTRLEN]; 602 SCIP_Longint maxval; 603 int decpower; 604 int i; 605 606 maxval = 1; 607 for( i = 0; i < width-1; ++i ) 608 maxval *= 10; 609 if( val < 0 ) 610 maxval /= 10; 611 decpower = 0; 612 while( ABS(val) >= maxval && decpower < MAXDECPOWER ) 613 { 614 decpower++; 615 val /= 1000; 616 } 617 (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%d" SCIP_LONGINT_FORMAT "%c", width-1, decpowerchar[decpower]); 618 619 if( width == 2 && val < 0 ) 620 SCIPmessageFPrintInfo(messagehdlr, file, "-%c", decpowerchar[decpower]); 621 else 622 SCIPmessageFPrintInfo(messagehdlr, file, (const char*)format, val); 623 } 624 } 625 626 /** displays an integer in decimal form fitting in a given width */ 627 void SCIPdispInt( 628 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 629 FILE* file, /**< output stream */ 630 int val, /**< value to display */ 631 int width /**< width to fit into */ 632 ) 633 { 634 SCIPdispLongint(messagehdlr, file, (SCIP_Longint)val, width); 635 } 636 637 638 static const char timepowerchar[] = {'s', 'm', 'h', 'd', 'y'}; 639 static const SCIP_Real timepowerval[] = {1.0, 60.0, 60.0, 24.0, 365.0}; 640 #define MAXTIMEPOWER 4 641 642 /** displays a time value fitting in a given width */ 643 void SCIPdispTime( 644 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 645 FILE* file, /**< output stream */ 646 SCIP_Real val, /**< value in seconds to display */ 647 int width /**< width to fit into */ 648 ) 649 { 650 assert(width >= 1); 651 652 if( width == 1 ) 653 { 654 if( val < 0.0 ) 655 SCIPmessageFPrintInfo(messagehdlr, file, "-"); 656 else if( val < 10.0 ) 657 SCIPmessageFPrintInfo(messagehdlr, file, "%.0f", val); 658 else 659 SCIPmessageFPrintInfo(messagehdlr, file, "+"); 660 } 661 else 662 { 663 char format[SCIP_MAXSTRLEN]; 664 SCIP_Longint maxval; 665 int timepower; 666 int i; 667 668 maxval = 1; 669 for( i = 0; i < width-1; ++i ) 670 maxval *= 10; 671 if( val < 0.0 ) 672 maxval /= 10; 673 timepower = 0; 674 while( REALABS(val) + 0.5 >= maxval && timepower < MAXTIMEPOWER ) 675 { 676 timepower++; 677 val /= timepowerval[timepower]; 678 } 679 if( REALABS(val) + 0.05 < maxval/100.0 ) 680 (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%d.1f%c", width-1, timepowerchar[timepower]); 681 else 682 (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%d.0f%c", width-1, timepowerchar[timepower]); 683 684 if( width == 2 && val < 0.0 ) 685 SCIPmessageFPrintInfo(messagehdlr, file, "-%c", timepowerchar[timepower]); 686 else 687 SCIPmessageFPrintInfo(messagehdlr, file, (const char*)format, val); 688 } 689 } 690