Max(), Min(), MaxF(), MinF()
ok... so now where are the updated versions?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
( The path to enlightenment and the PureBasic Survival Guide right here... )
Out of curiousity, is there a fast way to find the minimum and maximum values for a set of numbers larger than 2? For example, say I have a block of long values in memory (through AllocateMemory) and I want the min and max values of the first 8 long values. And then the min and max values for the next 8 long values - is there a nice and very fast way of doing this in asm? And maybe making it so it would work okay with byte or word variable types?
I'm probably asking for way too much but I thought I'd give it a shot
I'm probably asking for way too much but I thought I'd give it a shot

- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
@Xombie:
Maybe I am missing something here, but wouldn't a straight scan through the range checking for high/low values be faster than sorting or etc?
Eg: set minVal and maxVal to first element in range. Then step through next up to last element checking if value is less than min (change if true) or greater than max (change max if true).
Just one pass.
Maybe I am missing something here, but wouldn't a straight scan through the range checking for high/low values be faster than sorting or etc?
Eg: set minVal and maxVal to first element in range. Then step through next up to last element checking if value is less than min (change if true) or greater than max (change max if true).
Just one pass.
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Tension, you are right.
In order to get the higher o lower value from a list of values, I can not imagine another way to do that comparing one by one, and getting the higher (lower) from each comparing.
Xombie, look at the Min(), Max(), MinF() and MaxF() functions and it will be easy to implement what you want. Else ask me again and i will do an ASM function to do what you want
In order to get the higher o lower value from a list of values, I can not imagine another way to do that comparing one by one, and getting the higher (lower) from each comparing.
Xombie, look at the Min(), Max(), MinF() and MaxF() functions and it will be easy to implement what you want. Else ask me again and i will do an ASM function to do what you want

Well, yes. A looping works fine but here's what I was thinking. You'd be far more qualified to tell me if it's feasible for some super-nice ASM stuff to work better.
Say I have a 256 mb file. The file is full of alternating long values (or word or bytes depending on the file). I would need to loop through this file and take a variable number of long values and find the min & max. For the alternating values >_>;; It's audio stuff I'm playing with. So, wav samples.
Example - the 256 mb file. I would read in 200 byte chunks (ideally) find the min and max value of every odd long and then the min/max value of every even long in that 200 byte. And then read in the next 200 bytes and do min/max checking, repeat.
Maybe it'd be faster to read in 500kb at a time and then do the 200 byte min/max testing from that. I'm just giving an example.
Bah. ^_^ Does that make sense? I can't seem to explain it very well over text =_=
Say I have a 256 mb file. The file is full of alternating long values (or word or bytes depending on the file). I would need to loop through this file and take a variable number of long values and find the min & max. For the alternating values >_>;; It's audio stuff I'm playing with. So, wav samples.
Example - the 256 mb file. I would read in 200 byte chunks (ideally) find the min and max value of every odd long and then the min/max value of every even long in that 200 byte. And then read in the next 200 bytes and do min/max checking, repeat.
Maybe it'd be faster to read in 500kb at a time and then do the 200 byte min/max testing from that. I'm just giving an example.
Bah. ^_^ Does that make sense? I can't seem to explain it very well over text =_=
Try with 65536 (64KB) buffer per chan (2chans use 128KB) I found that very fast, even without using any asm code.
In any case, make sure the buffer size is block sized. i.e do not use say 32000 but use 32768 (32KB) etc etc.
As the filesystem caches in blocks natively (on windows)
So using block sizes speeds up that alot, eesp on large files.
Also, why do you need the Min and Max value?
If you are working with signed audio be it 16bit or 32bit samples,
So convert that to float and just do a Abs()
Remember a signed 16bit audio sample range from
-32768 as max negative with 0 as middle and 32767 as max positive.
In audio 0 is always the minimum, and if it is not the minimum tends to lie low, like um -10 and +23 etc.
By using Abs() you ensure that both positive and negative is taken into consideration.
So if you check the previous Abs() value with the current one and only store the new one if the Abs of that is higher.
You end up when the entire file is processed with the peak value.
And if you really need to know the minimum value you can store that too using the Abs only for the lowest (closest to 0) values.
Altough in pretty much any audio recording/sample you will most likely find 0 as the minimum value.
Personally I found using the BASS library nice, as you can tell it to return any file it support as 32bit float.
Which makes it very easy to process later on,
and since you don't have to convert from integer to float yourself
it's very easy and fast.
And you get a max negative value of -1.0 and max positive value of +1.0
Avoiding having to mess with converting -32768 to -1.0 and +32767 to +1.0
Using normal PB commands (no assembler) 64KB buffers per channel,
I was able analyze (get max peak) of a mp3 or normal wav (using BASS dll as my "reader" 10MB mp3's and 50+MB wavs in just a few seconds.
Heck even my passive 2chn stereo to 5chn surround dematrixer (or upmixer if you will) with proper passive surround decoding,
also all done with normal PB commands, several times faster than realtime.
It took less than 30 sec on even 10+MB mp'3s.
I can only imagine how fast it will be once I replace the loop bottle necks with asm.
Altough you could use 512KB buffers, I'm not sure the advantage would be that high.
First of all, more memory is used and moved around.
Second of all, half a meg chunks of data doesnt' get written to disk as fast as 64KB does.
Remember a lot of diskdrives don't have that much hardware diskcache memory.
And it has to read and write at the same time.
So try various sensible sizes like 32KB 64KB 128KB etc for the buffers.
Don't go to high as I said the disk cache isn that big.
And using sensible sizes allow the diskdrives cache features to really shine.
i.e if the diskdrive notice you read aa lot of 64K blocks sequentially from the same area on the disk, it will attempt when it has "free time" (like when you work with the data in memory)
to actually "read ahead" another &¤KB block or several,
so next time you fetch a 64KB block (or write) it will give you what is has pre fetched into the disk cache, reducing access time a lot.
If there is hardly any disk ativity by other programs and it's basically just your program reading and writing a lot of data,
you will notice that on modern hard disks with 1MB or more cache
totally make your files fly at insanely high speeds.
In addition I believe that windows itself (or the filesystem that is, particulary NTFS) also has it's own cache for read and write.
so that gives even more speed boost.
In any case, make sure the buffer size is block sized. i.e do not use say 32000 but use 32768 (32KB) etc etc.
As the filesystem caches in blocks natively (on windows)
So using block sizes speeds up that alot, eesp on large files.
Also, why do you need the Min and Max value?
If you are working with signed audio be it 16bit or 32bit samples,
So convert that to float and just do a Abs()
Remember a signed 16bit audio sample range from
-32768 as max negative with 0 as middle and 32767 as max positive.
In audio 0 is always the minimum, and if it is not the minimum tends to lie low, like um -10 and +23 etc.
By using Abs() you ensure that both positive and negative is taken into consideration.
So if you check the previous Abs() value with the current one and only store the new one if the Abs of that is higher.
You end up when the entire file is processed with the peak value.
And if you really need to know the minimum value you can store that too using the Abs only for the lowest (closest to 0) values.
Altough in pretty much any audio recording/sample you will most likely find 0 as the minimum value.
Personally I found using the BASS library nice, as you can tell it to return any file it support as 32bit float.
Which makes it very easy to process later on,
and since you don't have to convert from integer to float yourself
it's very easy and fast.
And you get a max negative value of -1.0 and max positive value of +1.0
Avoiding having to mess with converting -32768 to -1.0 and +32767 to +1.0
Using normal PB commands (no assembler) 64KB buffers per channel,
I was able analyze (get max peak) of a mp3 or normal wav (using BASS dll as my "reader" 10MB mp3's and 50+MB wavs in just a few seconds.
Heck even my passive 2chn stereo to 5chn surround dematrixer (or upmixer if you will) with proper passive surround decoding,
also all done with normal PB commands, several times faster than realtime.
It took less than 30 sec on even 10+MB mp'3s.
I can only imagine how fast it will be once I replace the loop bottle necks with asm.
Altough you could use 512KB buffers, I'm not sure the advantage would be that high.
First of all, more memory is used and moved around.
Second of all, half a meg chunks of data doesnt' get written to disk as fast as 64KB does.
Remember a lot of diskdrives don't have that much hardware diskcache memory.
And it has to read and write at the same time.
So try various sensible sizes like 32KB 64KB 128KB etc for the buffers.
Don't go to high as I said the disk cache isn that big.
And using sensible sizes allow the diskdrives cache features to really shine.
i.e if the diskdrive notice you read aa lot of 64K blocks sequentially from the same area on the disk, it will attempt when it has "free time" (like when you work with the data in memory)
to actually "read ahead" another &¤KB block or several,
so next time you fetch a 64KB block (or write) it will give you what is has pre fetched into the disk cache, reducing access time a lot.
If there is hardly any disk ativity by other programs and it's basically just your program reading and writing a lot of data,
you will notice that on modern hard disks with 1MB or more cache
totally make your files fly at insanely high speeds.
In addition I believe that windows itself (or the filesystem that is, particulary NTFS) also has it's own cache for read and write.
so that gives even more speed boost.
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Well, perhaps Rescator replied nice to your real question.
I would dump each chunk content to a memory block (using ReAllocateMemory() function and dumping 2-power as Rescator wrote "block sized").
Then i would work on that chunk getting the first odd value (you can difference odd and even values just testing bit #0 ) and comparing it with the next odd value, and then comparing the result with the next odd value, and so on ... until get the end of chunk.
BTW, to convert a range you can do this easy task (if you don't want to use bass lib, for example):
I would dump each chunk content to a memory block (using ReAllocateMemory() function and dumping 2-power as Rescator wrote "block sized").
Then i would work on that chunk getting the first odd value (you can difference odd and even values just testing bit #0 ) and comparing it with the next odd value, and then comparing the result with the next odd value, and so on ... until get the end of chunk.
BTW, to convert a range you can do this easy task (if you don't want to use bass lib, for example):
Code: Select all
value.l=-$6fbf; <- any value from -2^16 to (2^16)-1
val.f=$10000; <- 16 bit range. (If needed 32bit range you need a qword here)
!fild dword[v_value];convert value to float
!;fabs ;get its abs value, if wanted
!fdiv dword[v_val] ;convert range
!fstp dword[v_val] ;range converted to -1 -> +1
Debug val.f
So I would read in the samples for a certain 'block' (say 100 samples will equal 1 sample in memory) and find the largest absolute value of those samples? And then... graph the positive and negative value for that? So if the largest absolute value is 120 I would graph from 120 to -120 on the y-axis? Is it as simple as that?
I may look into something like BASS but I'm hoping to do this all with native PB code if possible. Should be fine with wave files but I guess I'll see what happens.
[Edit: And Psychophanta - thanks a lot for that code! That will be very helpful in my project!
]
I may look into something like BASS but I'm hoping to do this all with native PB code if possible. Should be fine with wave files but I guess I'll see what happens.
[Edit: And Psychophanta - thanks a lot for that code! That will be very helpful in my project!

- Michael Vogel
- Addict
- Posts: 2797
- Joined: Thu Feb 09, 2006 11:27 pm
- Contact:
Funny thing, as my knowledge of 80xxx assembler code must have be gone in the last centuries, I'll try to get some running code for re-learning...Psychophanta wrote:I have updated Min(), MinF(), Max() and MaxF() function.
Before was just working, now are "perfect".
But none of the codes from this thread are producing a correct result - Sgn just gives me (+)1 as the only result, and so on...
* Does one have a more conservative (running also on old Intel Pentium CPUs) code?
* One more question - has anybody seen a small summary how to have access to given parameters of a assembler procedure and how to return the result correctly?
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Hi , it must be updated to be used to ver. 4.0 
I did it (in the first post).
All the codes run on a 80386 or after. And it should also run on a 80286 with fpu 80186. Except where is a comment warn.

I did it (in the first post).
All the codes run on a 80386 or after. And it should also run on a 80286 with fpu 80186. Except where is a comment warn.
Just take a look to the forums. Or simply to ASM procedures here in my first post.Michael Vogel wrote:* One more question - has anybody seen a small summary how to have access to given parameters of a assembler procedure and how to return the result correctly?
- Michael Vogel
- Addict
- Posts: 2797
- Joined: Thu Feb 09, 2006 11:27 pm
- Contact:
- Michael Vogel
- Addict
- Posts: 2797
- Joined: Thu Feb 09, 2006 11:27 pm
- Contact:
Re: Max(), Min(), MaxF(), MinF()
I'm using the following routine for a while which works perfect for signed integer, does anyone know what have to be changed to get the result for unsigned values?
Debug Hex(uMax($55000000,$CC000000))
Debug Hex(uMax($55000000,$CC000000))
Code: Select all
Procedure.i iMax(val1.i, val2.i)
EnableASM
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
MOV eax,[p.v_val1]
CMP eax, [p.v_val2]
CMOVNG eax,[p.v_val2]
CompilerElse
MOV rax,[p.v_val1]
CMP rax, [p.v_val2]
CMOVNG rax, [p.v_val2]
CompilerEndIf
DisableASM
ProcedureReturn
EndProcedure