Python时间模块不精确加法

2024-06-25 22:40:09 发布

您现在位置:Python中文网/ 问答频道 /正文

免责声明:不确定标题是否合适,这是我的第一篇文章,所以我正在学习如何组织这篇文章

代码背景:

我使用Apophysis7x创建分形火焰(迭代图像),并在fractal Fr0st中打开.flame文件(该文件不渲染,它只是保存要在另一个编辑器中打开的信息),在这里我可以自动执行例如,不断旋转的迭代,从而创建动画。Fractal Fr0st使用python实现这种自动化,但是它们是常量。我制作音乐,并希望有一天完成我下面的代码有轮换的基础上,我的歌曲的BPM交替。我甚至在编辑与程序相关联的实际python文件之前,就开始自己编写代码来生成一个滴答声序列(该代码目前并不完全重要,但会在最后发布)

到目前为止关于问题的信息:

我马上就知道Python不是最快的语言,但是我不能100%确定我的代码是否不够高效,不能跟上我想要的输出。请看一看我的代码和注释,因为我试图解释,因为我可以彻底是怎么回事。你知道吗

定时器.py:

import time

#Feel free to test as you'd like
#Suppose we have a song at 140 Beat Per Minute (BPM) -> There is approximately 2.33 Beats Per Second (BPS)
#So it takes approximately 0.43 (s) per beat
#So  if freq = 0.43, leng = *length of song*
#This program should alternate printing "tick" "tock" (or some action that I hope to code in the future)
#The Tick Tock output should come out every (in this case) .43 seconds

class timer(object):
    "takes in a frequency and duration of loop in seconds"

    def __init__(self,freq,leng):
        "input a frequency and duration in seconds"
        #rounded to 2 decimal places

        self.freq= round (freq,2)
        self.leng= round (leng,2)

    def ticker (self):
        "Starts the time and loop to be broken when max time is reached"

        counter = 0 #recorded out of curiosity to check just how many loops were made overall
        ticker = 0 #alternates the "tick" "tock"
        initTime = time.time() #records the initial upon starting the loop
        rnded = 0 #initial rounded time set at 0 *see the first if statement below*


        while True:

            stop = time.time() #The time recorded during the loop *stopwatch so-to-speak*
            passed = stop - initTime #The time passed from initial launch to time during the loop

            if rnded == self.leng:
                "When the time that has passed reaches time limit print stats and break"

                return print("Loops:".ljust(10).rjust(14) + "Initial Time:".ljust(17).rjust(21) + "Time Stopped:".ljust(17).rjust(21)+ "Passed:".ljust(11).rjust(15) + "Total Ticks:".ljust(16).rjust(20) + "\n" + (str (counter) ).ljust(10).rjust(14) +(str (initTime) ).ljust(17).rjust(21)+ (str (stop) ).ljust(17).rjust(21)+(str (rnded) ).ljust(11).rjust(15) + (str (ticker) ).ljust(11).rjust(15) )

            elif round(passed,2) == rnded:
                "Prevents duplicates, ie: previous stopped at .9999 (1.0) and current loop sopped at 1.001 (1.0) skip" 
                #If your current value happened to be rounded to the previous value don't continue

                #uncomment bellow for debugging
                #print ("*TEST* \t Initiated: ", initTime, "\t Time stopped: ",stop, "\nTime passed: ", rnded, "\t Tick Counter: ", ticker, "\n ---")
                pass

            else:
                "Tick tock code"

                rnded = round(passed,2) #now set current time differnce value after being checked for duplicates
                if rnded % self.freq == 0 and rnded != 0:

                    "if the time passed mod the frequency is 0 continue to execute tick tock"

                    if ticker % 2 == 0:
                        #gives stats for debugging purposes, delete, after "tick" / "tock" if desired
                        #prints in the meantime in the future I would like an action to be done with music in another program as precise as possible

                        print ("Tick \t Initiated: ", initTime, "\t Time stopped: ",stop, "\nTime passed: ", rnded, "\t Tick Counter: ", ticker, "\n ---")

                    elif ticker % 2 == 1:
                        print ("Tock \t Initiated: ", initTime, "\t Time stopped: ",stop, "\nTime passed: ", rnded, "\t Tick Counter: ", ticker, "\n ---")

                    ticker +=1 #only increases if tick/tock was processed        

        counter += 1 #counts how many times loop was accessed, use this as you'd like

    def chngFreq(self, freq):
        'Changes current frequency'
        self.freq = round (freq,2)

    def chngLeng(self,leng):
        'Changes current duration'
        self.leng = round(leng,2)

示例1:

当频率变快时,输出会跳过多个“滴答声”/“滴答声”(我刚刚测试了一个例子,当频率为.01(s),总时间为4(s)时,应该总共有399个滴答声,但它只达到了5个滴答声。我的理论是,由于遍历循环确实需要时间(尽管时间很短),它可能会跳过一个记号,因为在从.01到.02的下一个记号被舍入之前,它可能是一个记号,但代码的处理速度不够快。我四舍五入到结尾以尽可能精确,并制作了“elif”部分以防止重复(参见上面的代码)

输出:

>>>s = timer(.01,4)
>>>s.ticker()
Tick     Initiated:  1502409793.6775877      Time stopped:  1502409793.6937597 
Time passed:  0.02   Tick Counter:  0 
---
Tock     Initiated:  1502409793.6775877      Time stopped:  1502409793.7562232 
Time passed:  0.08   Tick Counter:  1 
---
Tick     Initiated:  1502409793.6775877      Time stopped:  1502409793.8409605 
Time passed:  0.16   Tick Counter:  2 
 ---
Tock     Initiated:  1502409793.6775877      Time stopped:  1502409793.9940765 
Time passed:  0.32   Tick Counter:  3 
---
Tick     Initiated:  1502409793.6775877      Time stopped:  1502409794.9579115 
Time passed:  1.28   Tick Counter:  4 
---
Loops:        Initial Time:        Time Stopped:        Passed:        Total Ticks:    
5473896      1502409793.6775877    1502409797.680171    4.0            5

请注意,有时勾号只计算2^x,即:.01、.02、.04、.08、.16、.32…而不是:.01、.02、.03、.04、.05、.06…

我知道这不是我在代码中给出的示例,但每当我尝试更接近的频率(如.23或.01)时,它都是正确的,但是不管精度如何,频率越大,即:4.29,它就越有可能准确返回“滴答声”4.29、8.58、12.87等。。。你知道吗

例2

在下面的示例中,您可以看出它工作得非常好,因为它在两次滴答之间有较长的处理时间

>>>s = timer(1,4)
>>>s.ticker()
Tick     Initiated:  1502411198.8088021      Time stopped:  1502411199.8091898 
Time passed:  1.0    Tick Counter:  0 
---
Tock     Initiated:  1502411198.8088021      Time stopped:  1502411200.8089292 
Time passed:  2.0    Tick Counter:  1 
---
Tick     Initiated:  1502411198.8088021      Time stopped:  1502411201.81057 
Time passed:  3.0    Tick Counter:  2 
---
Tock     Initiated:  1502411198.8088021      Time stopped:  1502411202.8121786 
Time passed:  4.0    Tick Counter:  3 
---
Loops:        Initial Time:        Time Stopped:        Passed:        Total Ticks:    
5586557      1502411198.8088021   1502411202.8328226    4.0            4

如果有任何代码不清楚,请告诉我,但请务必先阅读每个注释,并在需要时运行代码/修改。

一旦我的上一个问题得到解决,我希望修改“如果x.animate:”部分的以下代码是在分形Fr0st使用

默认.py:

update_flame = False

while True:
    for x in flame.xform:
        if x.animate:
            x.rotate(-3)
    preview()

最后,提前感谢一百万我知道这真的很长,但我真的在努力理解python的情况/它是如何运行的,不管我的最终目标是什么。你知道吗

另外,如果其他方法更快/更有效,请告诉我。谢谢!!!你知道吗


Tags: theto代码selftimecountertickertick
1条回答
网友
1楼 · 发布于 2024-06-25 22:40:09

经过一番研究和一些简单的胡闹,我不仅找到了一些解决方案(我发现了真正的问题,而且还在发生),而且它还使我的代码缩短了很多。看一看。你知道吗

新的和改进的代码:

import time

#Feel free to test as you'd like
#Suppose we have a song at 140 Beat Per Minute (BPM) -> There is approximately 2.33 Beats Per Second (BPS)
#So it takes approximately 0.43 (s) per beat
#So  if freq = 0.43, leng = *length of song*
#This program should alternate printing "tick" "tock" (or some action that I hope to code in the future)
#The Tick Tock output should come out every (in this case) .43 seconds

class timer2(object):
    "takes in a frequency and duration of loop in seconds"

    def __init__(self,freq,leng):
        "input a frequency and duration in seconds"
        #rounded to 2 decimal places

        self.freq= round (freq,2)
        self.leng= round (leng,2)

    def ticker (self):
        "Starts the time and loop to be broken by freq"

        self.ticker = 0 #alternates the "tick" "tock"
        self.passed = 0 

        while round (self.passed,2) != self.leng:

            time.sleep(self.freq)

            if self.ticker % 2 == 0:
            #prints in the meantime in the future I would like an action to be done with music in another program as precise as possible

                print ("***TICK*** \t Tick Counter: ", self.ticker)

            elif self.ticker % 2 == 1:

                print ("***TOCK*** \t Tick Counter: ", self.ticker)

            self.ticker +=1 #only increases if tick/tock was processed

            self.passed += self.freq
            round (self.passed,2)

            print ("Time passed: ", self.passed, "(s)","\n  -")

        print ("Ticks: \t Time Passed: \n {} \t {}(s)".format(self.ticker,self.passed))

    def chngFreq(self, freq):
        'Changes current frequency'
        self.freq = round (freq,2)

    def chngLeng(self,leng):
        'Changes current duration'
        self.leng = round(leng,2)

请注意许多round()方法,我稍后将对此进行解释。你知道吗

我的基本输入:

>>>s = timer2(1,4)
>>>s.ticker()

这和预期的一样:1,2,3,4。然而,回到我最初想要的,如果我的频率很小,如.43,它将无法准确地工作。我包括第一个和最后4个输出为一个统一的频率.01。你知道吗

输出:

前四名:

>>>s = timer2(.01,4)
>>>s.ticker()
***TICK***   Tick Counter:  0
Time passed:  0.01 (s) 
 -
***TOCK***   Tick Counter:  1
Time passed:  0.02 (s) 
 -
***TICK***   Tick Counter:  2
Time passed:  0.03 (s) 
 -
***TOCK***   Tick Counter:  3
Time passed:  0.04 (s) 
 -

最后四个:

***TICK***   Tick Counter:  396
Times passed:  3.9699999999999593 (s) 
 -
***TOCK***   Tick Counter:  397
Times passed:  3.979999999999959 (s) 
 -
***TICK***   Tick Counter:  398
Times passed:  3.989999999999959 (s) 
 -
***TOCK***   Tick Counter:  399
Times passed:  3.9999999999999587 (s) 
 -
Ticks:   Time Passed: 
 400     3.9999999999999587(s)

请注意,在最末尾,所经过的时间应该是4(s),就像频率为1时一样。为什么时间过得真难看?前四个是好的,之后是长小数。我将打开另一个线程给出一个简单的循环(我仍然希望这是修改)。你知道吗

Python添加不正确,这很烦人。。。 .31+.01应为:.32及以后、.34、.35、.36、.37等。 即使把时间四舍五入到小数点后两位,它也不起作用。比如说,即使我不能修复难看的浮点值(.310000015684668),四舍五入应该是(.31),但是Python不会执行这个。你知道吗

***如果我消除了所有的舍入,我仍然得到长浮点值,因此它不是以ROUND()方法开始的***

相关问题 更多 >