如何通过测量float类型以秒为单位的时间间隔来防止浮点除数变成整数除法

问题描述 投票:2回答:1

我尝试使用Freebsd 12下的Perl版本5.20计算批量复制过程的传输速率。我得到了奇怪的结果,因为尽管使用了浮点除法来获得分形秒数,但亚秒间隔的值始终为零。持续时间条目。

详细信息:

为了进行测量,我使用DateTime :: Hires并在名为markTimediffTime的两个子例程中抽象了时间标记和差异。要查看正在执行的每步操作,请打印。

#!/usr/bin/env perl
use v5.20.1;
use warnings;
use strict;
use bigint;
use Time::HiRes qw(usleep nanosleep);
use DateTime::HiRes;
use Scalar::Util::Numeric;

# Set the total size of an object 
my $ttlSize = 1E3;

# Set the start time
my $startTime = &markTime('START');

# Sleep 12500 µs
usleep(12500);

# Calculate the elapsed time
my $runTime =  &diffTime($startTime);

# Calculate the rate in Bytes per second
my $rate =  $ttlSize/$runTime;

# Print it
print "RATE: $rate Bytes/s\n";

# Routine to set a timestamp 
sub markTime () {
    my $prefix =  shift;
    $prefix ='NOW' if not $prefix;
    my $now =  DateTime::HiRes->now;
    print"MARK.$prefix: ",$now->strftime( '%Y-%m-%d-%H-%M-%S.%N' ),"\n";
    return $now;
}

# Routine calc the difference
sub diffTime () {
    my $start = shift;
    # Calculate the duration
    my $now  =  &markTime('DIFF');
    my $dur  =  $now - $start;
    my $nano =  $dur->in_units('nanoseconds');

    # Original dateTime duration is integer
    print "DT.DUARTION: ",$nano," ns  IS.INT: ",
        Scalar::Util::Numeric::isint($nano),"\n";

    # Calc values for mano, micro, milli and seconds
    my $math_ns  = sprintf("%e",$nano);
    my $math_mus = sprintf("%e",$math_ns/1.0E3);
    my $math_ms  = sprintf("%e",$math_ns/1.0E6);
    my $math_s   = sprintf("%e",$math_ns/1.0E9);
    # Show the calculations
    print"MATH: ",$math_ns," ns\n";
    print"MATH: ",$math_mus," µs\n";
    print"MATH: ",$math_ms," ms\n";
    print"MATH: ",$math_s," s\n";
    # Check if the stuff ist float
    print "TIME.SECS: ", $math_ns*1.0E-9,
        " TIME.NANO: "   ,$math_ns,
        " IS.FLOAT: "  ,Scalar::Util::Numeric::isfloat($math_ns),"\n";
    return $math_s;
}

结果显示,尽管使用浮点除法运算,但runtime的亚秒浮点值已被除法“截断”,并且传输速率变为INF。

MARK.START: 2019-12-12-10-12-33.954870000
MARK.DIFF: 2019-12-12-10-12-33.968422000
DT.DUARTION: 13552000 ns  IS.INT: 1
MATH: 1.355200e+07 ns
MATH: 1.355200e+04 µs
MATH: 1.300000e+01 ms
MATH: 0.000000e+00 s
TIME.SECS: 0 TIME.NANO: 1.355200e+07 IS.FLOAT: 1
RATE: inf Bytes/s

为了获得$runtime变量的正确值0.013552,我该怎么办?

转储值:

---NANO---
SV = PVNV(0x8029cf9f0) at 0x8031c6408
  REFCNT = 1
  FLAGS = (IOK,NOK,POK,IsCOW,pIOK,pNOK,pPOK)
  IV = 13574000
  NV = 13574000
  PV = 0x8031ab5d0 "13574000"\0
  CUR = 8
  LEN = 10
  COW_REFCNT = 1

---MATH_NS---
SV = PV(0x802cb8900) at 0x8031c64e0
  REFCNT = 1
  FLAGS = (POK,IsCOW,pPOK)
  PV = 0x8031ab0f0 "1.357400e+07"\0
  CUR = 12
  LEN = 16
  COW_REFCNT = 2

---MATH_NS/1E9---
SV = PV(0x802d18b50) at 0x802f19bb8
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x8031d97c8
  SV = PVHV(0x800a8a560) at 0x8031d97c8
    REFCNT = 2
    FLAGS = (OBJECT,SHAREKEYS)
    STASH = 0x8016910d8 "Math::BigInt"
    ARRAY = 0x80323cdc0  (0:7, 2:1)
    hash quality = 62.5%
    KEYS = 2
    FILL = 1
    MAX = 7
    Elt "value" HASH = 0x7025df17
    SV = IV(0x803162b60) at 0x803162b70
      REFCNT = 1
      FLAGS = (ROK)
      RV = 0x801acca08
      SV = PVAV(0x800a894d8) at 0x801acca08
        REFCNT = 1
        FLAGS = (OBJECT)
        STASH = 0x801692e70 "Math::BigInt::Calc"
        ARRAY = 0x802d3bb18
        FILL = 0
        MAX = 0
        FLAGS = (REAL)
        Elt No. 0
        SV = IV(0x800b19ae8) at 0x800b19af8
          REFCNT = 1
          FLAGS = (IOK,pIOK)
          IV = 0
    Elt "sign" HASH = 0xc9f40697
    SV = PV(0x802cb8aa0) at 0x8031c6078
      REFCNT = 1
      FLAGS = (POK,IsCOW,pPOK)
      PV = 0x8017af0f0 "+"\0
      CUR = 1
      LEN = 10
      COW_REFCNT = 1
  PV = 0x8031d97c8 ""
  CUR = 0
  LEN = 0

diffTime与Math :: BigFloat的校正

所以我弄清楚了,在程序use bigint;中(现在在示例中被调用)是麻烦制造者,它将对所有部门产生影响。解决方法是:

sub diffTimeBigFloat () {
    my $start = shift;
    # Calculate the duration
    my $now  =  &markTime('DIFF');
    my $dur  =  $now->subtract_datetime_absolute($start);
    my $nano =  $dur->in_units('nanoseconds');
    # Original dateTime Duration
    print "DT.DUARTION: ",$nano," ns  IS.INT: ",
        Scalar::Util::Numeric::isint($nano),"\n";

    # Calc values for mano, micro, milli and seconds
    my $math_s  =  Math::BigFloat->new(sprintf("%sE-9",$nano));
    print"MATH: ",$math_s," s\n";
    print "TIME.SECS: ", $math_s, 
          " TIME.NANO: ", $math_s*1E9,
          " IS.FLOAT: " ,Scalar::Util::Numeric::isfloat($math_s),"\n";
    return $math_s;
}
perl datetime floating-point division
1个回答
1
投票

[use bigint;有效地导致1.0E9替换为Math::BigInt->new(1.0E9)

© www.soinside.com 2019 - 2024. All rights reserved.