import random import time from scipy.integrate import quad class Point: x: float y: float def __init__(self, point: (float, float)): self.x, self.y = point class LinearBounds: lower: float higher: float def __init__(self, lower: float, higher: float): self.lower = lower self.higher = higher def length(self) -> float: return self.higher - self.lower def get_random_value(self) -> float: return random.uniform(self.lower, self.higher) class Bounds: x: LinearBounds y: LinearBounds def __init__(self, x: LinearBounds, y: LinearBounds): self.x = x self.y = y def area(self) -> float: return self.x.length() * self.y.length() def get_random_point(self) -> Point: return Point((self.x.get_random_value(), self.y.get_random_value())) def function(x: float) -> float: return x**4-4*x**3+18*x**2-12*x-69 def getIsInside(p: Point) -> bool: y_0: float = function(p.x) if abs(y_0) > abs(p.y) and y_0*p.y >= 0: return True return False def getRealIntegral(bounds: LinearBounds) -> float: return quad(function, bounds.lower, bounds.higher)[0] def main(): startTime = time.time() pointsInside: int = 0 samples: int = 1000000 bounds = Bounds(LinearBounds(0, 20), LinearBounds(-100, 150000)) for i in range(samples): toTestPoint = bounds.get_random_point() if getIsInside(toTestPoint): pointsInside += 1 integral = (pointsInside / samples) * bounds.area() print(f"The approximated Integral of the function is: {integral:.2f}") real_value: float = getRealIntegral(bounds.x) print(f"The real Integral of the function is: {real_value:.2f}") error: float = abs(real_value-integral) print(f"That's an error of {error:.2f} or {(error/real_value)*100:.5f}% ") print(f"And the whole thing took {time.time()-startTime:.5f} Seconds for {samples} samples") if __name__ == "__main__": main()